绘制自定义控件
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
//
// 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
#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.对图片进行裁剪等