UIKIt与CoreGraphics

绘制自定义控件


这两种方式都可以绘制自定义控件





core Graphics颜色都是CGColor类型的


不填充颜色,只绘制边界,得到一个空心圆,颜色为紫色


设置左边圆形效果



绘制三角形


绘制矩形










有些自定义的时候需要自己更改坐标系,左边是core Graphics的坐标系,右边是UIKit的坐标系。




UIKIt





绘制三角形的






1.关于自定义绘制View的背景颜色的说明

默认情况下,自定义绘制View的背景颜色是黑色的,需要自己创建View之后设置View的背景颜色,正如Demo中所展现的那样:


UIView *customView = [[NERectangleView alloc] initWithFrame:rect];

customView.backgroundColor = [UIColor lightGrayColor];

实际上也可以在drawRect方法中设置背景色如下:

- (void)drawRect:(CGRect)rect {

// 获取上下文

CGContextRef context = UIGraphicsGetCurrentContext();

// 设置View的背景色

CGContextSetFillColorWithColor(context, [UIColor purpleColor].CGColor);

CGContextFillRect(context, rect);

}


在`UIBezierPath.h`中定义了更多用于构造`UIBezierPath`的方法, 包括:

创建矩形的Path   

+ (instancetype)bezierPathWithRect:(CGRect)rect;

椭圆形的path  

+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;

圆角矩形的path   

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; // rounds all corners with the same horizontal and vertical radius

+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;

弧线段的path   

+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;


除了绘制标准的矩形、椭圆形等形状外,还可以通过方法

void CGContextAddCurveToPoint(CGContextRef __nullable c, CGFloat cp1x,  CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y);

来画各种曲线段,该方法添加了一段贝塞尔曲线,关于贝塞尔曲线,请参见: 

https://zh.wikipedia.org/wiki/%E8%B2%9D%E8%8C%B2%E6%9B%B2%E7%B7%9A




Quartz2D

### 1. 顺时针、逆时针问题

课堂中提到

void CGContextAddArc(CGContextRef __nullable c, CGFloat x, CGFloat y,

    CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise);


由于CoreGraphics的坐标系不同于UIKit的坐标系,所以当clockwise传1的时候,是逆时针;而当clockwise传0的时候,反而是顺时针;

值得提醒的是,我们上一节学习过的UIBezierPath是属于UIKit的一部分,因此是UIKit的坐标系,因此,下面的代码

UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(120, 100) radius:20 startAngle:0 endAngle: 45 * M_PI / 180 clockwise:YES];

得到的是一段顺时针的从0到45度的弧线;也就是对于UIBezierPath的这个方法而言,clockwise传递YES的时候,是顺时针;传递NO的时候,是逆时针.

下面两个开源库可以直接用于绘制各种iOS图表: 


1. https://github.com/kevinzhow/PNChart

2. https://github.com/danielgindi/Charts

在开源库YYKit (https://github.com/ibireme/YYKit) 的 `YYKit/YYKit/Base/UIKit/UIImage+YYAdd.m` (https://github.com/ibireme/YYKit/blob/master/YYKit/Base/UIKit/UIImage%2BYYAdd.m)里,有大量利用Quartz 2D API进行绘制的例子; 大家可以参考,也可以直接利用YYKit已经封装好的方法.

此外,除了使用Quartz 2D API来一步步绘制控件外,通常也会使用CAShapeLayer结合CGPath来实现类似的效果

函数`CGContextEOFillPath`采用`even-odd fill rule`(奇偶填充规则)来填充路径;关于奇偶填充规则的更多介绍,参见:

1. http://www.enfocus.com/manuals/ReferenceGuide/PP/13/zhCN/zh-cn/common/ppr/concept/c_aa1141812.html

2. https://en.wikipedia.org/wiki/Even%E2%80%93odd_rule

3. https://developer.mozilla.org/zh-CN/docs/Web/SVG/Attribute/fill-rule





可以通过Quartz2D





绘制自定义进度条代码如下

//

//  NECircleProgressViewController.m

//  QuartzDemo

//

//  Created by Netease on 16/7/11.

//  Copyright © 2016年 Netease. All rights reserved.

//

#import "NECircleProgressViewController.h"

#import "NECircleChart.h"

@interface NECircleProgressViewController ()

@property (nonatomic, strong) NECircleChart *circleChart;

@property (nonatomic, strong) UISlider *slider;

@end

@implementationNECircleProgressViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    self.view.backgroundColor = [UIColor lightGrayColor];

    [self addSubView];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    // Get the new view controller using [segue destinationViewController].

    // Pass the selected object to the new view controller.

}

*/

- (void)addSubView {

    CGFloat startX = (CGRectGetWidth(self.view.bounds) - 280) / 2;

    self.slider = [[UISlider alloc] initWithFrame:CGRectMake(startX, 80, 280, 40)];

    self.slider.minimumValue = 1;

    self.slider.maximumValue = 100;

    self.slider.value= 72;

    [self.slider addTarget:self action:@selector(updateCurrentValue:) forControlEvents:UIControlEventValueChanged];

    [self.view addSubview:self.slider];


    CGRect rect = CGRectMake(0, 150.0, CGRectGetWidth(self.view.frame), 200.0);

    self.circleChart = [[NECircleChart alloc] initWithFrame:rect

                                                      total:@100

                                                    current:@(self.slider.value)

                                                  clockwise:YES];

    self.circleChart.backgroundColor = [UIColor clearColor];

    [self.circleChart setStrokeColor:[UIColor orangeColor]];

    [self.view addSubview:self.circleChart];

}

- (void)updateCurrentValue:(UISlider*)slider {

    self.circleChart.current = @(slider.value);

    [self.circleChart setNeedsDisplay];

}

@end

//

//  NECircleChart.h

//  QuartzDemo

//

//  Created by Netease on 16/7/9.

//  Copyright © 2016年 Netease. All rights reserved.

//

#import

#import "NEDemoDefinitions.h"

@interfaceNECircleChart :UIView

- (instancetype)initWithFrame:(CGRect)frame

                        total:(NSNumber*)total

                      current:(NSNumber*)current

                    clockwise:(BOOL)clockwise;

/**

 *  定义总的值,当前的值以及是否顺时针.

 */

@property (nonatomic, strong) NSNumber *total;

@property (nonatomic, strong) NSNumber *current;

@property (nonatomic, assign) BOOL clockwise;

/**

 *  线条颜色,宽度以及显示比例信息的Label.

 */

@property (nonatomic, strong) UIColor *strokeColor;

@property (nonatomic, strong) NSNumber *lineWidth;

@property (nonatomic, strong) UILabel *valueLabel;

@end

//

//  NECircleChart.m

//  QuartzDemo

//

//  Created by Netease on 16/7/9.

//  Copyright © 2016年 Netease. All rights reserved.

//

#import "NECircleChart.h"

@implementation NECircleChart

- (instancetype)initWithFrame:(CGRect)frame

                        total:(NSNumber*)total

                      current:(NSNumber*)current

                    clockwise:(BOOL)clockwise {

    self= [selfinitWithFrame:frame];

    if(self) {

        _total= total;

        _current= current;

        _strokeColor = [UIColor orangeColor];

        _clockwise= clockwise;

        _lineWidth= @(8.0);

    }


    return self;

}

- (void)drawRect:(CGRect)rect {

   if([_total integerValue]<=0)

   {

       return;

   }

   //获取上下文

    CGContextRef context=UIGraphicsGetCurrentContext();


    // 起始弧度与结束弧度

    CGFloatstartAngle=270.0f;

    CGFloat angleOffset = 360 *( [_current floatValue] / [_total floatValue]);//当前转动的值占整个的百分比

    CGFloatcurEndAngle =_clockwise? startAngle+angleOffset:startAngle-angleOffset;



    //添加弧线

    //注意: 这里的clockwise有所不同由于坐标系的原因,0才真正表示UIKit里的顺时针

    CGFloat centerX = CGRectGetWidth(self.frame) / 2.0f;

    CGFloat centerY = CGRectGetHeight(self.frame) / 2.0f;

    CGFloatradius = centerX < centerY ? centerX : centerY;


    radius -= ([_lineWidthfloatValue] / 2.0f);


    CGContextAddArc(context, centerX, centerY, radius,DEGREES_TO_RADIANS(startAngle),DEGREES_TO_RADIANS(curEndAngle),self.clockwise?0:1);


    //设置颜色与线条属性

    CGContextSetFillColorWithColor(context, [UIColor clearColor].CGColor);

    CGContextSetLineWidth(context, [_lineWidth floatValue]);

    CGContextSetLineCap(context, kCGLineCapRound);

    CGContextSetStrokeColorWithColor(context, _strokeColor.CGColor);


    //绘制弧线

    CGContextStrokePath(context);


    // 添加表示当前值的Label

    if(nil==self.valueLabel) {

        self.valueLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100.0, 50.0)];

        [self.valueLabel setTextAlignment:NSTextAlignmentCenter];

        [self.valueLabel setFont:[UIFont boldSystemFontOfSize:16.0f]];

        [self.valueLabel setTextColor:[UIColor grayColor]];

        [self.valueLabel setBackgroundColor:[UIColor clearColor]];

        [self.valueLabel setCenter:CGPointMake(self.frame.size.width/2.0f, self.frame.size.height/2.0f)];

        [self addSubview:self.valueLabel];

    }


    CGFloat percentage=100* [self.current floatValue]/[_total floatValue];


    self.valueLabel.text=[NSString stringWithFormat:@"%@%%", @((NSInteger)percentage)];




}

@end




点击相应区域,添加边框

//

//  NEPieChartViewController.m

//  QuartzDemo

//

//  Created by Netease on 16/7/11.

//  Copyright © 2016年 Netease. All rights reserved.

//

#import "NEPieChartViewController.h"

#import "NEPieChartView.h"

#import "NEPieChartItem.h"

@interface NEPieChartViewController ()

@property (nonatomic, strong) NEPieChartView *pieChart;

@end

@implementationNEPieChartViewController

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    self.view.backgroundColor = [UIColor lightGrayColor];

    [self addSubView];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    // Get the new view controller using [segue destinationViewController].

    // Pass the selected object to the new view controller.

}

*/

- (void)addSubView {

    CGFloatcircleRadius = 120;

    CGRectrect =CGRectMake(CGRectGetWidth(self.view.frame) / 2.0 - circleRadius, 115, circleRadius * 2, circleRadius * 2);

    self.pieChart = [[NEPieChartView alloc] initWithFrame:rect];

    self.pieChart.radius = 100;

    self.pieChart.innerRadius = 33;

    self.pieChart.clickedRadius = 110;

    self.pieChart.itemList = [self buildTestData];

    self.pieChart.backgroundColor = [UIColor clearColor];

    [self.view addSubview:self.pieChart];

}

#pragma mark - 构造测试数据

- (NSArray *)buildTestData {

    NSMutableArray *itemList = [[NSMutableArray alloc] init];


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"开发";

        item.value= 10;

        item.color= [UIColorcolorWithRed:77.0 / 255.0green:216.0 / 255.0blue:122.0 / 255.0alpha:1.0f];

        [itemListaddObject:item];

    }

    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"测试";

        item.value= 20;

        item.color = [UIColor redColor];

        [itemListaddObject:item];

    }


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"产品";

        item.value= 30;

        item.color = [UIColor blueColor];

        [itemListaddObject:item];

    }


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"运维";

        item.value= 40;

        item.color = [UIColor purpleColor];

        [itemListaddObject:item];

    }


    CGFloatsumValue;

    for(NEPieChartItem*item in itemList) {

        sumValue += item.value;

    }


    if(sumValue > 0) {

        CGFloatstartPercentage = 0;

        for(NEPieChartItem*iteminitemList) {

            item.startPercentage= startPercentage;

            item.endPercentage= item.startPercentage+ item.value/ sumValue;

            startPercentage = item.endPercentage;

        }

    }


    returnitemList;

}

@end

//

//  NEPieChartItem.h

//  QuartzDemo

//

//  Created by NetEase on 16/7/7.

//  Copyright © 2016年 NetEase. All rights reserved.

//

#import

#import

@interfaceNEPieChartItem :NSObject

/**

 *  饼图上显示的名字

 */

@property (nonatomic, copy) NSString *name;

/**

 *  饼图上这一部分的颜色

 */

@property (nonatomic, strong) UIColor *color;

/**

 *  饼图上这一部分所展的值或比例. Demo中总值为100,因此value即为比例.

 *  实际项目中需要计算总的值与每一份所占的比例.

 */

@property (nonatomic, assign) CGFloat value;

/**

 *  饼图上所占比例的起始值与结束值

 */

@property (nonatomic, assign) CGFloat startPercentage;

@property (nonatomic, assign) CGFloat endPercentage;

@end

//

//  NEPieChartView.h

//  QuartzDemo

//

//  Created by NetEase on 16/7/7.

//  Copyright © 2016年 NetEase. All rights reserved.

//

#import

@class NEPieChartItem;

@interfaceNEPieChartView :UIView

/**

 *  要展示的数据.

 */

@property (nonatomic, strong) NSArray *itemList;

/**

 *  界面的配置

 */

@property (nonatomic, assign) CGFloat radius;

@property (nonatomic, assign) CGFloat innerRadius;

@property (nonatomic, assign) CGFloat clickedRadius;

@property (nonatomic, assign) CGFloat sliceSpace;

@end

//

//  NEPieChartView.m

//  QuartzDemo

//

//  Created by NetEase on 16/7/7.

//  Copyright © 2016年 NetEase. All rights reserved.

//

#import "NEPieChartView.h"

#import "NEPieChartItem.h"

@interfaceNEPieChartView()

@property(nonatomic,assign) NSInteger selectedIndex;

@end

@implementation NEPieChartView

- (instancetype)initWithFrame:(CGRect)frame {

    self= [superinitWithFrame:frame];

    if(self) {

        // 设置默认的属性

        // 半径

        _radius = 100;


        // 内圆半径

        _innerRadius = 33;


        // 选中后的外圆半径

        _clickedRadius = 110;


        // 每项间距

        _sliceSpace = 0;


        _selectedIndex = -1;

    }


    return self;

}

- (void)drawRect:(CGRect)rect {

    [selfdrawData:self.itemList];

}

- (void)drawData:(NSArray *)itemList {

    if([itemListcount] == 0) {

        return;

    }


    // 上下文

    CGContextRef context = UIGraphicsGetCurrentContext();


    // 半径与圆点

    CGFloatradius =self.radius;

    CGFloatinnerRadius =self.innerRadius;

    CGFloatsliceSpace =self.sliceSpace;

    CGFloat centerX = CGRectGetMidX(self.bounds);

    CGFloat centerY = CGRectGetMidY(self.bounds);

    CGFloatdeg2Rad = (M_PI/ 180.0);


    // 起始弧度

    CGFloatrotationAngle = 270;

    CGFloatangle = 0.0;

    NSIntegerindex = 0;

    for(NEPieChartItem* iteminitemList) {

        CGFloatvalue = item.value;

        CGFloatsliceAngle = value * 360.0 / 100;

        if(fabs(value) > 0.000001) {

            // 起始角度与结束角度.

            CGFloatstartAngle = rotationAngle + (angle + sliceSpace / 2.0);

            CGFloatsweepAngle = (sliceAngle - sliceSpace / 2.0);

            if(sweepAngle < 0.0) {

                sweepAngle = 0.0;

            }

            CGFloatendAngle = startAngle + sweepAngle;


            // 外圆

            CGFloatoutRadius = radius;

            CGMutablePathRef path = CGPathCreateMutable();

            CGPathMoveToPoint(path,nil, centerX, centerY);

            CGPathAddArc(path,nil, centerX, centerY, outRadius, startAngle * deg2Rad, endAngle * deg2Rad,false);

            CGPathCloseSubpath(path);


            // 内圆

            if(innerRadius > 0.0) {

                CGPathMoveToPoint(path,nil, centerX, centerY);

                CGPathAddArc(path,nil, centerX, centerY, innerRadius, startAngle * deg2Rad, endAngle * deg2Rad,false);

                CGPathCloseSubpath(path);

            }


            // 绘制

            CGContextBeginPath(context);

            CGContextAddPath(context, path);

            CGContextSetFillColorWithColor(context, item.color.CGColor);

            CGContextEOFillPath(context);


            // 画选中部分.

            if(index ==self.selectedIndex) {

                CGMutablePathRef path = CGPathCreateMutable();

                CGPathMoveToPoint(path,nil, centerX, centerY);

                CGPathAddArc(path,nil, centerX, centerY,_clickedRadius, startAngle * deg2Rad, endAngle * deg2Rad,false);

                CGPathCloseSubpath(path);


                if(innerRadius > 0.0) {

                    CGPathMoveToPoint(path,nil, centerX, centerY);

                    CGPathAddArc(path,nil, centerX, centerY, innerRadius, startAngle * deg2Rad, endAngle * deg2Rad,false);

                    CGPathCloseSubpath(path);

                }


                CGContextBeginPath(context);

                CGContextAddPath(context, path);

                CGContextSetFillColorWithColor(context, [item.color colorWithAlphaComponent:0.5].CGColor);

                CGContextEOFillPath(context);

            }

        }


        index ++;

        angle += sliceAngle;

    }

}

#pragma mark - Touch

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event

{

    for(UITouch*touchintouches) {

        CGPointtouchLocation = [touchlocationInView:self];

        [selfdidTouchAt:touchLocation];

    }

}

- (void)didTouchAt:(CGPoint)touchLocation {

    if(self.selectedIndex!= -1) {

        self.selectedIndex= -1;

        [self setNeedsDisplay];

        return;

    }


    CGFloat centerX = CGRectGetMidX(self.bounds);

    CGFloat centerY = CGRectGetMidY(self.bounds);

    CGPointcircleCenter =CGPointMake(centerX, centerY);

    CGFloatdistanceFromCenter =sqrtf(powf((touchLocation.y- circleCenter.y),2) +powf((touchLocation.x- circleCenter.x),2));


    if(distanceFromCenter <_innerRadius) {

        self.selectedIndex= -1;

    }else{

        CGFloatpercentage = [selffindPercentageOfAngleInCircle:circleCenterfromPoint:touchLocation];


        for(NSIntegerindex = 0; index < [self.itemListcount]; index ++) {

            CGFloatendPercentage = [self.itemList[index]endPercentage];

            if(percentage <= endPercentage) {

                self.selectedIndex= index;

                break;

            }

        }

    }


    [self setNeedsDisplay];

}

- (CGFloat)findPercentageOfAngleInCircle:(CGPoint)center fromPoint:(CGPoint)reference {

    CGFloatangleOfLine =atanf((reference.y- center.y) / (reference.x- center.x));

    CGFloatpercentage = (angleOfLine +M_PI/2)/(2 *M_PI);

    return(reference.x- center.x) > 0 ? percentage : percentage + .5;

}

@end

如果让ui进行改变,需要调用setNeedsDisplay,会重新调用drawRect进行绘制。


截屏,云课堂demo,quartz2D使用demo里面有


#pragma mark - 截屏

+ (UIImage*)imageFromView:(UIView*)view {

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0);//获取当前屏幕(创建上下文)

    [viewdrawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];//在这个区域内把view给画出来(方法是在ios7之后有效)


    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();


    returnimage;

}


#import

@interfaceUIImage (NEKits)

// 截屏

+ (UIImage*)imageFromView:(UIView*)view;

// 给图片加圆角

- (UIImage*)imageWithRoundedCorner:(CGFloat)radius

                               size:(CGSize)size;

// 给图片加圆角同时添加边框颜色

- (UIImage*)imageWithRoundedCorner:(CGFloat)radius

                               size:(CGSize)size

                        borderWidth:(CGFloat)borderWidth

                        borderColor:(UIColor*)borderColor;

@end


#import "UIImage+NEKits.h"

@implementationUIImage (NEKits)

#pragma mark - 截屏

+ (UIImage*)imageFromView:(UIView*)view {

    UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, 0);//获取当前屏幕(创建上下文)

    [viewdrawViewHierarchyInRect:view.bounds afterScreenUpdates:NO];//在这个区域内把view给画出来(方法是在ios7之后有效)


    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();


    returnimage;

}

#pragma mark - 给图片加圆角

- (UIImage*)imageWithRoundedCorner:(CGFloat)radius

                               size:(CGSize)size {

    return [self imageWithRoundedCorner:radius size:size borderWidth:0 borderColor:nil];

}

- (UIImage*)imageWithRoundedCorner:(CGFloat)radius

                               size:(CGSize)size

                        borderWidth:(CGFloat)borderWidth

                        borderColor:(UIColor*)borderColor {

    UIGraphicsBeginImageContextWithOptions(size, NO, 0);


    // 获取当前上下文

    CGContextRef context = UIGraphicsGetCurrentContext();


    // 切圆角 Path

    CGRectrect =CGRectMake(0, 0, size.width, size.height);

    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)];

    CGContextAddPath(context, path.CGPath);

    CGContextClip(context);

    [pathclosePath];


    // 绘制图片

    [selfdrawInRect:rect];


    // 添加边框

    if(borderColor !=nil) {

        UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:rect byRoundingCorners:UIRectCornerAllCorners cornerRadii:CGSizeMake(radius, radius)];

        [borderPathsetLineWidth:borderWidth];

        [borderColorsetStroke];

        [borderPathstroke];

    }


    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();


    returnimage;

}

@end

//

//  NEPieChartViewController.m

//  QuartzDemo

//

//  Created by Netease on 16/7/11.

//  Copyright © 2016年 Netease. All rights reserved.

//

#import "NESnapShotController.h"

#import "NEPieChartView.h"

#import "NEPieChartItem.h"

#import "UIImage+NEKits.h"

@interface NESnapShotController ()

@property (nonatomic, strong) NEPieChartView *pieChart;

@property (nonatomic, strong) UIButton *snapShotBtn;

@end

@implementationNESnapShotController

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view.

    self.view.backgroundColor = [UIColor lightGrayColor];

    [self addSubView];

}

- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

/*

#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {

    // Get the new view controller using [segue destinationViewController].

    // Pass the selected object to the new view controller.

}

*/

- (void)addSubView {

    CGFloatcircleRadius = 120;

    CGRectrect =CGRectMake(CGRectGetWidth(self.view.frame) / 2.0 - circleRadius, 135, circleRadius * 2, circleRadius * 2);

    self.pieChart = [[NEPieChartView alloc] initWithFrame:rect];

    self.pieChart.radius = 100;

    self.pieChart.innerRadius = 33;

    self.pieChart.clickedRadius = 110;

    self.pieChart.itemList = [self buildTestData];

    self.pieChart.backgroundColor = [UIColor lightGrayColor];

    [self.view addSubview:self.pieChart];


    self.snapShotBtn = [[UIButton alloc] initWithFrame:CGRectMake(30, 80, 120, 44)];

    [self.snapShotBtn setTitle:@"截屏" forState:UIControlStateNormal];

    self.snapShotBtn.titleLabel.textColor = [UIColor whiteColor];

    self.snapShotBtn.titleLabel.font = [UIFont systemFontOfSize:16];

    self.snapShotBtn.layer.cornerRadius = 15;

    self.snapShotBtn.layer.masksToBounds = YES;

    self.snapShotBtn.layer.borderWidth = 1;

    self.snapShotBtn.layer.borderColor = [UIColor redColor].CGColor;

    [self.snapShotBtn addTarget:self action:@selector(onClickSnapShotBtn:) forControlEvents:UIControlEventTouchUpInside];

    [self.view addSubview:self.snapShotBtn];

}

// 展示PieChart.

- (NSArray *)buildTestData {

    NSMutableArray *itemList = [[NSMutableArray alloc] init];


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"开发";

        item.value= 10;

        item.color= [UIColorcolorWithRed:77.0 / 255.0green:216.0 / 255.0blue:122.0 / 255.0alpha:1.0f];

        [itemListaddObject:item];

    }


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"测试";

        item.value= 20;

        item.color = [UIColor redColor];

        [itemListaddObject:item];

    }


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"产品";

        item.value= 30;

        item.color = [UIColor blueColor];

        [itemListaddObject:item];

    }


    {

        NEPieChartItem *item = [[NEPieChartItem alloc] init];

        item.name=@"运维";

        item.value= 40;

        item.color = [UIColor purpleColor];

        [itemListaddObject:item];

    }


    CGFloatsumValue;

    for(NEPieChartItem*iteminitemList) {

        sumValue += item.value;

    }


    if(sumValue > 0) {

        CGFloatstartPercentage = 0;

        for(NEPieChartItem*iteminitemList) {

            item.startPercentage= startPercentage;

            item.endPercentage= item.startPercentage+ item.value/ sumValue;

            startPercentage = item.endPercentage;

        }

    }


    returnitemList;

}

#pragma mark - Actions

- (void)onClickSnapShotBtn:(id)sender {

    UIImage *image = [UIImage imageFromView:self.pieChart];

    if(nil!= image) {

        [selfsaveImageToPhotos:image];

    }

}

#pragma mark - Save Files to Album 

- (void)saveImageToPhotos:(UIImage*)image {

    UIImageWriteToSavedPhotosAlbum(image,self,@selector(image:didFinishSavingWithError:contextInfo:),NULL);

}

- (void)image:(UIImage*)image didFinishSavingWithError:(NSError*)error contextInfo:(void*)contextInfo {

    NSString*msg =nil;

    if(error !=nil) {

        msg =@"保存截屏图片失败";

    }else{

        msg =@"保存截屏图片成功";

    }


    [self showAlertMessage:@"保存截屏图片"];

}

- (void)showAlertMessage:(NSString*)message {

    UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"提示" message:message preferredStyle:UIAlertControllerStyleAlert];

    [controlleraddAction:[UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:nil]];


    [self presentViewController:controller animated:YES completion:nil];

}

#pragma mark - Save Image Files

- (void)saveImage:(UIImage*)image toCacheFile:(NSString*)fileName {

    if(nil== image || [fileNamelength] == 0) {

        return;

    }


    NSData *data = UIImagePNGRepresentation(image);

    if(data) {

        NSFileManager *fileManager = [NSFileManager defaultManager];

        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);

        NSString *filePath = [paths[0] stringByAppendingPathComponent:@"default"];

        if(![fileManagerfileExistsAtPath:filePath]) {

            [fileManagercreateDirectoryAtPath:filePath withIntermediateDirectories:YES attributes:nil error:NULL];

        }


        NSString *file = [filePath stringByAppendingPathComponent:fileName];

        if([fileManagerfileExistsAtPath:file]) {

            [fileManagerremoveItemAtPath:fileerror:nil];

        }


        NSLog(@"保存文件到%@", file);

        [fileManagercreateFileAtPath:filecontents:dataattributes:nil];

    }

}

@end


1.自己绘制控件

2.画出一张图片

3.对图片进行裁剪等

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,525评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,203评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,862评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,728评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,743评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,590评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,330评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,244评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,693评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,885评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,001评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,723评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,343评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,919评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,042评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,191评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,955评论 2 355

推荐阅读更多精彩内容