绘制饼状图主要思想
循环添加
主要计算结束弧度 数据的本分比*360 + 开始弧度
开始绘制圆弧,链接中心,设置随机色,fill填充 最后很重要的异步就是数据转换,把结束弧度赋值给开始弧度。
参考代码
- (void)drawRect:(CGRect)rect {
NSArray *data = @[ @30, @15, @5 , @17 , @3, @10, @20];
CGFloat radius = MIN(self.bounds.size.width/2, self.bounds.size.height/2);
CGFloat start = 0;
CGFloat end = 0;
CGPoint centerP = CGPointMake(rect.size.width/2, rect.size.height/2);
for (int i = 0; i < data.count; i++) {
//主要是计算结束弧度,数据的百分数*360 加上开始弧度
end = [data[i]floatValue ]/100 * (2 * M_PI) + start;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:centerP radius:radius startAngle:start endAngle:end clockwise:YES];
[path addLineToPoint:centerP];
//添加颜色
[[UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0) green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0) alpha:1.0]set ];
[path fill];
#pragma mark 这是很重要的角度转换
start = end;
}
}
柱状图实现思想
主要计算 x h
w 就是平均宽度 rect /(数据数量的2倍-1);
循环添加矩形
x 就是 平均宽度 * 2 * i
h 就是百分比*矩形的高度
y rect - h;
实例代码
- (void)drawRect:(CGRect)rect {
NSArray *data = @[@300, @150.65, @55.3, @507.7, @95.8, @700, @650.65];
//设置宽度
CGFloat w = rect.size.width / (data.count * 2 - 1);
for (int i = 0; i < data.count; i++) {
//x就等于 2*w*i
CGFloat x = w * i * 2;
//高度就等于 百分比 * rect的高度
CGFloat h = [data[i] floatValue]/1000 * rect.size.height;
//y 就等于屏幕的高度 - 他的高度
CGFloat y = rect.size.height - h;
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, w, h)];
[[UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0) green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0) alpha:1.0]set ];
[path fill];
}
}
//自定义下载进度
主要计算结果弧度
给veiw中添加一个记录数据的属性
在storyboard中 连接 属性 slider 和 自定义的View(他里面设置一个记录数据的属性)
把sliderl接一个方法 在里面用它的Value给view的属性赋值
在draw中绘制圆弧
看需求在哪个开始绘图
重写记录属性的参数,并进行重绘 ,就能实现随着slider变化了
如果想显示下载多少,可以用一个label来显示,用懒加载添加label
记得用strong,
设置frame时设置成view一样大,字中间显示
在重写记录数据的那个方法中计算它的百分比 就用,数据*100就可以
实例代码
- (void)drawRect:(CGRect)rect {
// Drawing code
//创建路径
CGPoint point = CGPointMake(rect.size.width/2, rect.size.height/2);
CGFloat radius = MIN(rect.size.width/2, rect.size.height/2);
CGFloat statr = -M_PI_2;
CGFloat end = 2 * M_PI * self.count + statr;
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:point radius:radius startAngle:statr endAngle:end clockwise:YES];
[path addLineToPoint:point];
[[UIColor redColor] set];
[path fill];
UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:point radius:radius - 10 startAngle:statr endAngle:end clockwise:YES];
[path1 addLineToPoint:point];
[self.backgroundColor set];
[path1 fill];
}
给属性赋值
- (IBAction)changeVale:(UISlider *)sender {
self.xlImageView.count = sender.value;
}
//属性得用strong 懒加载
- (UILabel *)label{
if (_label == nil) {
_label = [[UILabel alloc]init];
_label.textColor = [UIColor brownColor];
_label.font = [UIFont systemFontOfSize:25.f];
_label.textAlignment = NSTextAlignmentCenter;
[self addSubview:_label];
}
return _label;
}
//设置frame
- (void)layoutSubviews
{
[super layoutSubviews];
self.label.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
}
//重写count
- (void)setCount:(CGFloat)count
{
_count = count;
//设置内容
self.label.text = [NSString stringWithFormat:@"%.2f%%",self.count * 100];
[self setNeedsDisplay];
}
//自定义
自定义图片框
声明一个继承UIVIew的类
声明一个image的属性
在 drawRect中绘制image
重写image,并进行重绘
这就完成了自定义imageView。就可以用他进行添加图片。
示例
.h中有个image属性
- (void)setImage:(UIImage *)image
{
_image = image;
//重绘
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect {
[self.image drawInRect:rect];
}
引用头文件,就可以像UIImageView一样使用了
用触摸事件和绘图 小案例实现思想
案例1.简易画板的实现思想
1.>在touchesBegan中根据触摸对象获取当前的点
开启划线路径,把当前点击的点设置为线的起始点。
在touchesMoved中也根据触摸对象获取当前点击的点,把他设置为线的线段。在里面执行重绘。
在drawRect中渲染。就能把线绘画出来,但是发现,只能存储一个根线。
2.>解决办法,把线都存储到数组中,在touchesBegan中存储线的起点,在touchesMoved中根据数组的有序的性质,获取它最后一个元素添加线条。所以修改他添加线的方法。
因为存储在数组中,所以在drawRect中forin循环 (什么类型)BezierPath *path in (数组中);这样就可以绘制多条线段了。
3.>线宽根据slider来设置,连线在viewDidLoad中,slider连个属性(主要为了给线宽设置一个初始值)和方法(把自身传过来,方便用他自身value的属性),把绘制的UIView的类连个属性,在它里面设置一个熟悉,用来接收slider的值。(CGFloat类型)
在touchesBegan中设置线宽,如果早drawRect中设置了线宽,那么一画线的线段,那么线宽都会变成当前的线宽
4.>实现点击按钮中的颜色改变线的颜色
在继承UIVIew中在添加一个lineColor的属性,把按钮连线到storyboard中,把按钮自己传过来。设置属性的颜色为按钮的背景颜色。(按钮的方法都可以连接到一个方法中);因为颜色设置有些特殊,所以自定义一个BezierPath 在里面设置一个属性lineColor
这样的话就把前面的BezierPath 都改成自定义的BezierPath。
在颜色按钮中设置Views中颜色的属性,在touchesBegan中给自定义的颜色属性赋值,(因为是自定义的所以在drawRect中用路径设置线的颜色)这样颜色就可以根据按钮的颜色来设定了
清屏
在UIView中来一个方法,移除数组中所有元素,然后在item的方法中,调用这个方法就行。
回退
和清屏差不多,移除最后一个数组元素就行
然后调用方法
橡皮擦
设置成背景颜色,然后在item的方法中调用就可以了
保存就是截屏然后存相册或者沙河
代码
继承UIView
.h
@interface XLView : UIView
@property (nonatomic,assign) CGFloat lineWinth;
@property (nonatomic,strong) UIColor *lineColor;
- (void) clean;
- (void) banck;
- (void) eraser;
@end
.m
#import "XLView.h"
#import "XLBezierPath.h"
@interface XLView ()
@property (nonatomic,strong) XLBezierPath *path;
@property (nonatomic,strong) NSMutableArray *paths;
@end
@implementation XLView
- (NSMutableArray *)paths
{
if (_paths == nil) {
_paths = [NSMutableArray array];
}
return _paths;
}
//手指按下
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//获取触摸对象
UITouch *touch = touches.anyObject;
//根据触摸对象获取当前点击的点
CGPoint locp = [touch locationInView:touch.view];
//开启路径
self.path = [XLBezierPath bezierPath];
//当前点击的点就是开始的点
[self.path moveToPoint:locp];
//设置线宽
self.path.lineWidth = self.lineWinth;
//设置颜色
self.path.line9Color = self.lineColor;
//保存到数组
[self.paths addObject:self.path];
}
//手指移动
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
//获取触摸对象
UITouch *touch = touches.anyObject;
//根据触摸对象获当前点
CGPoint currentP = [touch locationInView:touch.view];
//划线
[[self.paths lastObject] addLineToPoint:currentP];
//重绘
[self setNeedsDisplay];
}
//手指抬起
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
}
- (void)drawRect:(CGRect)rect {
// [self.path stroke];
//既然在数组中,要绘制那就要绘制所有的,那就循环绘制
for (XLBezierPath *path in self.paths) {
//设置连接样式
path.lineJoinStyle = kCGLineJoinRound;
//设置线的头样式
path.lineCapStyle = kCGLineCapRound;
//设置颜色
[path.line9Color set];
[path stroke];
}
}
- (void) clean
{
[self.paths removeAllObjects];
[self setNeedsDisplay];
}
- (void) banck
{
[self.paths removeLastObject];
[self setNeedsDisplay];
}
- (void) eraser
{
self.lineColor = self.backgroundColor;
[self setNeedsDisplay];
}
自定义的
@interface XLBezierPath : UIBezierPath
@property (nonatomic,strong) UIColor *line9Color;
@end
storyboard中
@interface ViewController ()
@property (weak, nonatomic) IBOutlet XLView *xlView;
@property (weak, nonatomic) IBOutlet UISlider *slider;
@end
@implementation ViewController
//给lView中的lineWinth赋值
- (IBAction)changeVslue:(UISlider *)sender
{
self.xlView.lineWinth = sender.value;
}
- (void)viewDidLoad {
[super viewDidLoad];
//赋一个初始值
self.xlView.lineWinth = self.slider.value;
}
- (IBAction)btcClick:(UIButton *)sender
{
self.xlView.lineColor = sender.backgroundColor;
}
- (IBAction)cleanBtn:(id)sender
{
[self.xlView clean];
}
- (IBAction)eraserBtnClick:(id)sender
{
[self.xlView eraser];
}
- (IBAction)backBtnClick:(id)sender
{
[self.xlView banck];
}
- (BOOL)prefersStatusBarHidden
{
return YES;
}
- (IBAction)saver:(id)sender {
//开启图形上下文路径
UIGraphicsBeginImageContextWithOptions(self.xlView.bounds.size, NO, 0.0);
//获取图形上下文路径
CGContextRef ref = UIGraphicsGetCurrentContext();
//通过layer的renderInContext 把内容渲染到图形上下文中
[self.xlView.layer renderInContext:ref];
//获取图片
UIImage *getImage = UIGraphicsGetImageFromCurrentImageContext();
//关闭图形上下文路径
UIGraphicsEndImageContext();
//保存相册
UIImageWriteToSavedPhotosAlbum(getImage, self, @selector(image:didFinishSavingWithError:contextInfo:), @"nihao");
//保存沙河
//开始路径
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//保存文件路径
NSString *filePath = [path stringByAppendingPathComponent:@"asd.png"];
//保存 之前还要转换 成
NSData *imageDate = UIImagePNGRepresentation(getImage);
[imageDate writeToFile:filePath atomically:YES];
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
NSString *str = @"保存成功";
if (error)
{
str = @"保存失败";
}else
{
str = @"保存成功";
}
NSLog(@"%@",str);
}