首页 文章 精选 留言 我的

精选列表

搜索[2d],共1192篇文章
优秀的个人博客,低调大师

iOS - Quartz 2D 画板绘制

1、绘制画板 1.1 绘制简单画板 PaintBoardView.h @interface PaintBoardView : UIView @end PaintBoardView.m @interface PaintBoardView () /// 路径 @property (nonatomic, strong) UIBezierPath *path; /// 保存所有路径的数组 @property (nonatomic, strong) NSMutableArray *pathsArrayM; @end @implementation PaintBoardView /// 初始化 - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor whiteColor]; } return self; } /// 触摸开始 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸起始点位置 CGPoint startPoint = [touches.anyObject locationInView:self]; // 添加路径描绘起始点 [self.path moveToPoint:startPoint]; // 添加一条触摸路径描绘 [self.pathsArrayM addObject:self.path]; } /// 触摸移动 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置 CGPoint touchPoint = [touches.anyObject locationInView:self]; // 添加路径描绘 [self.path addLineToPoint:touchPoint]; // 刷新视图 [self setNeedsDisplay]; } /// 触摸结束 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取绘制结果 UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0); CGContextRef ctx = UIGraphicsGetCurrentContext(); [self.layer renderInContext:ctx]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSData *data = UIImagePNGRepresentation(image); [data writeToFile:@"/Users/JHQ0228/Desktop/Images/pic.png" atomically:YES]; } /// 触摸取消 - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event { [self touchesEnded:touches withEvent:event]; } /// 绘制图形 - (void)drawRect:(CGRect)rect { for (UIBezierPath *path in self.pathsArrayM) { // 绘制路径 [path stroke]; } } /// 懒加载 - (UIBezierPath *)path { if (_path == nil) { _path = [UIBezierPath bezierPath]; } return _path; } - (NSMutableArray *)pathsArrayM { if (_pathsArrayM == nil) { _pathsArrayM = [NSMutableArray array]; } return _pathsArrayM; } @end ViewController.m // 创建画板 CGRect frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 200); PaintBoardView *paintBoard = [[PaintBoardView alloc] initWithFrame:frame]; [self.view addSubview:paintBoard]; 效果 1.2 绘制画板封装 具体实现代码见 GitHub 源码 QExtension QPaintBoardPath.h @interface QPaintBoardPath : UIBezierPath /// 线的颜色 @property (nonatomic, strong) UIColor *pathColor; /// 线的宽度 @property (nonatomic, assign) CGFloat pathWidth; @end QPaintBoardPath.m @implementation QPaintBoardPath @end QPaintBoardView.h @interface QPaintBoardView : UIView /// 画线的宽度,default is 1,max is 30 @property (nonatomic, assign) CGFloat paintLineWidth; /// 画笔的颜色,default is blackColor @property (nonatomic, strong) UIColor *paintLineColor; /// 画板的颜色,default is whiteColor @property (nonatomic, strong) UIColor *paintBoardColor; /** * 创建画板视图控件,获取绘画结果 * * @param frame 画板视图控件 frame * @param lineWidth 画笔的线宽,default is 1,max is 30 * @param lineColor 画笔的颜色,default is blackColor * @param boardColor 画板的颜色,default is whiteColor * @param result 绘画结果 * * @return 手势锁视图控件 */ + (instancetype)q_paintBoardViewWithFrame:(CGRect)frame lineWidth:(CGFloat)lineWidth lineColor:(nullable UIColor *)lineColor boardColor:(nullable UIColor *)boardColor paintResult:(void (^)(UIImage * _Nullable image))result; /** * 创建简单画板视图控件 * * @param frame 画板视图控件 frame * * @return 手势锁视图控件 */ + (instancetype)q_paintBoardViewWithFrame:(CGRect)frame; /** * 获取绘画结果 * * @return 绘画结果图片 */ - (UIImage * _Nullable)q_getPaintImage; /** * 清除绘画结果 */ - (void)q_clear; /** * 撤销绘画结果 */ - (void)q_back; @end QPaintBoardView.m #import "QPaintBoardPath.h" @interface QPaintBoardView () /// 路径 @property (nonatomic, strong, nullable) QPaintBoardPath *path; /// 保存所有路径的数组 @property (nonatomic, strong) NSMutableArray *pathsArrayM; /// 绘画结果 @property (nonatomic, copy) void (^resultBlock)(UIImage * _Nullable); /// 按钮工具条 @property (nonatomic, strong) UIView *toolView; /// 画笔设置视图 @property (nonatomic, strong) UIView *brushSetingView; /// 颜色选择视图 @property (nonatomic, strong) UIScrollView *colorSelectedView; /// 画板设置视图 @property (nonatomic, strong) UIScrollView *boardSetingView; /// 记录线的颜色 @property (nonatomic, strong) UIColor *lastPaintLineColor; /// 记录线的宽度 @property (nonatomic, assign) CGFloat lastPaintLineWidth; @end @implementation QPaintBoardView #pragma mark - 创建画板 /// 创建画板视图控件,获取绘画结果 + (instancetype)q_paintBoardViewWithFrame:(CGRect)frame lineWidth:(CGFloat)lineWidth lineColor:(nullable UIColor *)lineColor boardColor:(nullable UIColor *)boardColor paintResult:(void (^)(UIImage * _Nullable image))result { QPaintBoardView *paintBoardView = [[self alloc] init]; // CGRect tmpFrame = frame; // tmpFrame.size.height = frame.size.height + 44; paintBoardView.frame = frame; paintBoardView.paintLineWidth = (lineWidth > 30 ? 30 : lineWidth) ? : 1; paintBoardView.paintLineColor = lineColor ? : [UIColor blackColor]; paintBoardView.paintBoardColor = boardColor ? : [UIColor whiteColor]; paintBoardView.resultBlock = result; return paintBoardView; } /// 创建简单画板视图控件 + (instancetype)q_paintBoardViewWithFrame:(CGRect)frame { QPaintBoardView *paintBoardView = [[self alloc] initWithFrame:frame]; paintBoardView.paintLineWidth = 1; paintBoardView.paintLineColor = [UIColor blackColor]; paintBoardView.paintBoardColor = [UIColor whiteColor]; return paintBoardView; } #pragma mark - 自定义画板 /// 初始化,自定义画板界面 - (instancetype)init { if (self = [super init]) { self.clipsToBounds = YES; // 添加工具按钮视图 self.toolView = [[UIView alloc] init]; self.toolView.backgroundColor = [UIColor blackColor]; [self addSubview:self.toolView]; NSArray *imageNames = @[@"btn_brush", @"btn_board", @"btn_eraser", @"btn_back", @"btn_clear", @"btn_save"]; NSArray *selectedImageNames = @[@"btn_brush_pressed", @"btn_board_pressed", @"btn_eraser_pressed"]; for (NSUInteger i = 0; i < 6; i++) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.tag = i; [button setBackgroundImage:[self q_getBundleImageWithName:imageNames[i]] forState:UIControlStateNormal]; [button addTarget:self action:@selector(toolButtonClick:) forControlEvents:UIControlEventTouchUpInside]; [self.toolView addSubview:button]; if (i < 3) { [button setBackgroundImage:[self q_getBundleImageWithName:selectedImageNames[i]] forState:UIControlStateSelected]; } } // 添加画笔设置视图 self.brushSetingView = [[UIView alloc] init]; self.brushSetingView.backgroundColor = [UIColor grayColor]; [self addSubview:self.brushSetingView]; [self sendSubviewToBack:self.brushSetingView]; UIView *widthBackView = [[UIView alloc] init]; widthBackView.layer.borderWidth = 1; widthBackView.layer.borderColor = [UIColor lightGrayColor].CGColor; UIView *widthView = [[UIView alloc] init]; [widthBackView addSubview:widthView]; [self.brushSetingView addSubview:widthBackView]; UISlider *widthSlider = [[UISlider alloc] init]; widthSlider.thumbTintColor = [UIColor orangeColor]; [widthSlider addTarget:self action:@selector(widthSliderClick:) forControlEvents:UIControlEventValueChanged]; [self.brushSetingView addSubview:widthSlider]; UIButton *colorSelectedBtn = [[UIButton alloc] init]; colorSelectedBtn.layer.borderWidth = 1; colorSelectedBtn.layer.borderColor = [UIColor lightGrayColor].CGColor; [colorSelectedBtn addTarget:self action:@selector(colorSelectedBtnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.brushSetingView addSubview:colorSelectedBtn]; // 添加画笔颜色选择视图 self.colorSelectedView = [[UIScrollView alloc] init]; self.colorSelectedView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.3]; self.colorSelectedView.showsHorizontalScrollIndicator = NO; [self addSubview:self.colorSelectedView]; [self sendSubviewToBack:self.colorSelectedView]; NSArray *colorArray = @[[UIColor blackColor], [UIColor whiteColor], [UIColor redColor], [UIColor greenColor], [UIColor blueColor], [UIColor cyanColor], [UIColor magentaColor], [UIColor orangeColor], [UIColor yellowColor], [UIColor darkGrayColor], [UIColor lightGrayColor], [UIColor brownColor], [UIColor grayColor], [UIColor purpleColor]]; for (NSUInteger i = 0; i < 14; i++) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.layer.borderWidth = 1; button.layer.borderColor = [UIColor lightGrayColor].CGColor; [button setBackgroundColor:colorArray[i]]; [button addTarget:self action:@selector(colorSelectedClick:) forControlEvents:UIControlEventTouchUpInside]; [self.colorSelectedView addSubview:button]; } // 添加画板设置视图 self.boardSetingView = [[UIScrollView alloc] init]; self.boardSetingView.backgroundColor = [UIColor grayColor]; self.boardSetingView.showsHorizontalScrollIndicator = NO; [self addSubview:self.boardSetingView]; [self sendSubviewToBack:self.boardSetingView]; for (NSUInteger i = 0; i < 14; i++) { UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.layer.borderWidth = 1; button.layer.borderColor = [UIColor lightGrayColor].CGColor; [button setBackgroundColor:colorArray[i]]; [button addTarget:self action:@selector(boardColorSelectedClick:) forControlEvents:UIControlEventTouchUpInside]; [self.boardSetingView addSubview:button]; } } return self; } /// 布局子控件 - (void)layoutSubviews { [super layoutSubviews]; if (self.subviews.count) { // 设置工具按钮视图 self.toolView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 44); for (NSUInteger i = 0; i < 6; i++) { CGFloat margin = (self.bounds.size.width - 44 * 6) / 7; CGFloat x = margin + (margin + 44) * i; self.toolView.subviews[i].frame = CGRectMake(x, 0, 44, 44); } // 设置画笔设置视图 self.brushSetingView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60); self.brushSetingView.subviews[0].frame = CGRectMake(15, 15, 30, 30); self.brushSetingView.subviews[0].layer.cornerRadius = 15; self.brushSetingView.subviews[0].layer.masksToBounds = YES; CGFloat w = self.paintLineWidth; self.brushSetingView.subviews[0].subviews[0].frame = CGRectMake(15 - w / 2, 15 - w / 2, w, w); self.brushSetingView.subviews[0].subviews[0].layer.cornerRadius = w / 2; self.brushSetingView.subviews[0].subviews[0].layer.masksToBounds = YES; self.brushSetingView.subviews[0].subviews[0].backgroundColor = self.paintLineColor; self.brushSetingView.subviews[1].frame = CGRectMake(60, 15, self.bounds.size.width - 60 - 80, 32); UISlider *slider = self.brushSetingView.subviews[1]; slider.value = self.paintLineWidth / 30; self.brushSetingView.subviews[2].frame = CGRectMake(self.bounds.size.width - 60, 15, 50, 30); self.brushSetingView.subviews[2].backgroundColor = self.paintLineColor; // 设置画笔颜色选择视图 self.colorSelectedView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60); self.colorSelectedView.contentSize = CGSizeMake(14 * (50 + 20) + 20, 50); for (NSUInteger i = 0; i < 14; i++) { CGFloat x = 20 + (20 + 50) * i; self.colorSelectedView.subviews[i].frame = CGRectMake(x, 10, 50, 40); } // 设置画板设置视图 self.boardSetingView.frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60); self.boardSetingView.contentSize = CGSizeMake(14 * (50 + 20) + 20, 50); for (NSUInteger i = 0; i < 14; i++) { CGFloat x = 20 + (20 + 50) * i; self.boardSetingView.subviews[i].frame = CGRectMake(x, 10, 50, 40); } } } /// 工具按钮点击事件处理 - (void)toolButtonClick:(UIButton *)btn { switch (btn.tag) { case 0: { // 画笔设置 [self exitEraseState]; if (btn.isSelected == NO) { [self hideBoardSetingView]; [self showColorSelectedView]; [self showBrushSetingView]; } else { [self hideColorSelectedView]; [self hideBrushSetingView]; } break; } case 1: { // 画板设置 [self exitEraseState]; if (btn.isSelected == NO) { [self hideColorSelectedView]; [self hideBrushSetingView]; [self showBoardSetingView]; } else { [self hideBoardSetingView]; } break; } case 2: { // 擦除 [self hideBoardSetingView]; [self hideColorSelectedView]; [self hideBrushSetingView]; if (btn.selected == NO) { [self enterEraseState]; } else { [self exitEraseState]; } break; } case 3: { // 撤销 [self hideBoardSetingView]; [self hideColorSelectedView]; [self hideBrushSetingView]; [self q_back]; break; } case 4: { // 清除 [self hideBoardSetingView]; [self hideColorSelectedView]; [self hideBrushSetingView]; [self exitEraseState]; [self q_clear]; break; } case 5: { // 获取绘制结果 [self hideBoardSetingView]; [self hideColorSelectedView]; [self hideBrushSetingView]; [self exitEraseState]; if (self.resultBlock) { self.resultBlock([self q_getPaintImage]); } break; } default: break; } } /// 画笔线宽设置按钮点击事件处理 - (void)widthSliderClick:(UISlider *)slider { if (slider.value == 0) { self.paintLineWidth = 1; } else { self.paintLineWidth = slider.value * 30; } CGFloat w = self.paintLineWidth; self.brushSetingView.subviews[0].subviews[0].frame = CGRectMake(15 - w / 2, 15 - w / 2, w, w); self.brushSetingView.subviews[0].subviews[0].layer.cornerRadius = w / 2; } /// 画笔颜色选择按钮点击事件处理 - (void)colorSelectedBtnClick:(UIButton *)btn { if (btn.selected == NO) { [self showColorSelectedView]; } else { [self hideColorSelectedView]; } } /// 画笔颜色选择点击响应事件处理 - (void)colorSelectedClick:(UIButton *)btn { self.paintLineColor = btn.backgroundColor; self.brushSetingView.subviews[0].subviews[0].backgroundColor = btn.backgroundColor; self.brushSetingView.subviews[2].backgroundColor = btn.backgroundColor; } /// 画板颜色选择点击响应事件处理 - (void)boardColorSelectedClick:(UIButton *)btn { self.paintBoardColor = btn.backgroundColor; } /// 显示画笔设置视图 - (void)showBrushSetingView { UIButton *setBrushBtn = self.toolView.subviews[0]; if (setBrushBtn.selected == NO) { setBrushBtn.selected = YES; [UIView animateWithDuration:0.2 animations:^{ CGRect frame = CGRectMake(0, self.bounds.size.height - 44 - 60, self.bounds.size.width, 60); self.brushSetingView.frame = frame; }]; } } /// 隐藏画笔设置视图 - (void)hideBrushSetingView { UIButton *setBrushBtn = self.toolView.subviews[0]; if (setBrushBtn.selected) { setBrushBtn.selected = NO; [UIView animateWithDuration:0.2 animations:^{ CGRect frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60); self.brushSetingView.frame = frame; }]; } } // 显示画笔颜色选择视图 - (void)showColorSelectedView { UIButton *colorSelectedBtn = self.brushSetingView.subviews[2]; if (colorSelectedBtn.selected == NO) { colorSelectedBtn.selected = YES; [UIView animateWithDuration:0.2 animations:^{ CGRect frame = CGRectMake(0, self.bounds.size.height - 44 - 60 - 60, self.bounds.size.width, 60); self.colorSelectedView.frame = frame; }]; } } /// 隐藏画笔颜色选择视图 - (void)hideColorSelectedView { UIButton *colorSelectedBtn = self.brushSetingView.subviews[2]; if (colorSelectedBtn.selected) { colorSelectedBtn.selected = NO; [UIView animateWithDuration:0.2 animations:^{ CGRect frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60); self.colorSelectedView.frame = frame; }]; } } /// 显示画板设置视图 - (void)showBoardSetingView { UIButton *setBoardBtn = self.toolView.subviews[1]; if (setBoardBtn.selected == NO) { setBoardBtn.selected = YES; [UIView animateWithDuration:0.2 animations:^{ CGRect frame = CGRectMake(0, self.bounds.size.height - 44 - 60, self.bounds.size.width, 60); self.boardSetingView.frame = frame; }]; } } /// 隐藏画板设置视图 - (void)hideBoardSetingView { UIButton *setBoardBtn = self.toolView.subviews[1]; if (setBoardBtn.selected) { setBoardBtn.selected = NO; [UIView animateWithDuration:0.2 animations:^{ CGRect frame = CGRectMake(0, self.bounds.size.height - 44, self.bounds.size.width, 60); self.boardSetingView.frame = frame; }]; } } /// 进入擦除状态 - (void)enterEraseState { UIButton *setEraseBtn = self.toolView.subviews[2]; if (setEraseBtn.selected == NO) { setEraseBtn.selected = YES; self.lastPaintLineColor = self.paintLineColor; self.paintLineColor = self.paintBoardColor; self.lastPaintLineWidth = self.paintLineWidth; self.paintLineWidth = self.paintLineWidth + 5; } } /// 退出擦除状态 - (void)exitEraseState { UIButton *setEraseBtn = self.toolView.subviews[2]; if (setEraseBtn.isSelected) { setEraseBtn.selected = NO; self.paintLineColor = self.lastPaintLineColor; self.paintLineWidth = self.lastPaintLineWidth; } } #pragma mark - 绘制图案 /// 触摸开始 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { if (self.subviews.count) { [self hideColorSelectedView]; [self hideBrushSetingView]; [self hideBoardSetingView]; } // 获取触摸起始点位置 CGPoint startPoint = [touches.anyObject locationInView:self]; // 添加路径描绘起始点 [self.path moveToPoint:startPoint]; // 记录线的属性 self.path.pathColor = self.paintLineColor; self.path.pathWidth = self.paintLineWidth; // 添加一条触摸路径描绘 [self.pathsArrayM addObject:self.path]; } /// 触摸移动 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置 CGPoint touchPoint = [touches.anyObject locationInView:self]; // 添加路径描绘 [self.path addLineToPoint:touchPoint]; // 刷新视图 [self setNeedsDisplay]; } /// 触摸结束 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 销毁 path self.path = nil; } /// 触摸取消 - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event { [self touchesEnded:touches withEvent:event]; } /// 绘制图形,只要调用 drawRect 方法就会把之前的内容全部清空 - (void)drawRect:(CGRect)rect { for (QPaintBoardPath *path in self.pathsArrayM) { // 绘制路径 path.lineWidth = path.pathWidth; [path.pathColor setStroke]; path.lineCapStyle = kCGLineCapRound; path.lineJoinStyle = kCGLineJoinRound; [path stroke]; } } /// 获取绘画结果 - (UIImage * _Nullable)q_getPaintImage { UIImage *image = nil; CGSize boardSize = self.bounds.size; if (self.subviews.count) { boardSize.height = self.bounds.size.height - 44; } if (self.pathsArrayM.count) { UIGraphicsBeginImageContextWithOptions(boardSize, NO, 0); CGContextRef ctx = UIGraphicsGetCurrentContext(); [self.layer renderInContext:ctx]; image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); } return image; } /// 清除绘画结果 - (void)q_clear { if (self.pathsArrayM.count) { [self.pathsArrayM removeAllObjects]; [self setNeedsDisplay]; } } /// 撤销绘画结果 - (void)q_back { if (self.pathsArrayM.count) { [self.pathsArrayM removeLastObject]; [self setNeedsDisplay]; } } /// 懒加载 - (QPaintBoardPath * _Nullable)path { // path 每次绘制完成后需要销毁,否则无法清除之前绘制的路径 if (_path == nil) { _path = [QPaintBoardPath bezierPath]; } return _path; } - (NSMutableArray *)pathsArrayM { if (_pathsArrayM == nil) { _pathsArrayM = [NSMutableArray array]; } return _pathsArrayM; } /// 设置属性值 - (void)setPaintBoardColor:(UIColor *)paintBoardColor { _paintBoardColor = paintBoardColor; self.backgroundColor = paintBoardColor; } /// 加载 bundle 中的图片 - (UIImage *)q_getBundleImageWithName:(NSString *)name { NSString *bundlePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"QPaintBoardView.bundle"]; UIImage *image = [[UIImage imageWithContentsOfFile:[bundlePath stringByAppendingPathComponent:name]] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; return image; } @end 1、创建简单画板 // 创建简单画板 CGRect frame = CGRectMake(20, 50, self.view.bounds.size.width - 40, 200); QPaintBoardView *paintBoardView = [QPaintBoardView q_paintBoardViewWithFrame:frame]; // 可选属性值设置 paintBoardView.paintLineWidth = 5; // default is 1 paintBoardView.paintLineColor = [UIColor redColor]; // default is blackColor paintBoardView.paintBoardColor = [UIColor cyanColor]; // default is whiteColor [self.view addSubview:paintBoardView]; self.paintBoardView = paintBoardView; // 撤销绘画结果 [self.paintBoardView q_back]; // 清除绘画结果 [self.paintBoardView q_clear]; // 获取绘画结果 UIImage *image = [self.paintBoardView q_getPaintImage]; 效果 2、创建画板 // 创建画板 QPaintBoardView *paintBoard = [QPaintBoardView q_paintBoardViewWithFrame:self.view.bounds lineWidth:0 lineColor:nil boardColor:nil paintResult:^(UIImage * _Nullable image) { if (image) { NSData *data = UIImagePNGRepresentation(image); [data writeToFile:@"/Users/JHQ0228/Desktop/Images/pic.png" atomically:YES]; } }]; [self.view addSubview:paintBoard]; 效果

优秀的个人博客,低调大师

iOS - Quartz 2D 下载进度按钮绘制

1、绘制下载进度按钮 具体实现代码见 GitHub 源码 QExtension QProgressButton.h @interface QProgressButton : UIButton /// 进度值,范围 0 ~ 1 @property (nonatomic, assign) CGFloat progress; /// 进度终止状态标题,一旦设置了此标题进度条就会停止 @property (nonatomic, strong) NSString *stopTitle; /** * 创建带进度条的按钮 * * @param frame 按钮的 frame 值 * @param title 进按钮的标题 * @param lineWidth 进度条的线宽,default is 2 * @param lineColor 进度条线的颜色,default is greenColor * @param textColor 进度值的颜色,default is blackColor * @param backColor 按钮的背景颜色,default is clearColor * @param isRound 按钮是否显示为圆形,default is YES * * @return 带进度条的按钮 */ + (instancetype)q_progressButtonWithFrame:(CGRect)frame title:(NSString *)title lineWidth:(CGFloat)lineWidth lineColor:(nullable UIColor *)lineColor textColor:(nullable UIColor *)textColor backColor:(nullable UIColor *)backColor isRound:(BOOL)isRound; @end QProgressButton.m @interface QProgressButton () /// 进度条的线宽 @property (nonatomic, assign) CGFloat lineWidth; /// 进度条线的颜色 @property (nonatomic, strong) UIColor *lineColor; /// 按钮的背景颜色 @property (nonatomic, strong) UIColor *backColor; /// 按钮是否显示为圆形 @property (nonatomic, assign, getter=isRound) BOOL round; @end @implementation QProgressButton /// 创建带进度条的按钮 + (instancetype)q_progressButtonWithFrame:(CGRect)frame title:(NSString *)title lineWidth:(CGFloat)lineWidth lineColor:(nullable UIColor *)lineColor textColor:(nullable UIColor *)textColor backColor:(nullable UIColor *)backColor isRound:(BOOL)isRound { QProgressButton *progressButton = [[self alloc] init]; progressButton.lineWidth = lineWidth ? : 2; progressButton.lineColor = lineColor ? : [UIColor colorWithRed:76/255.0 green:217/255.0 blue:100/255.0 alpha:1.0]; progressButton.backColor = backColor ? : [UIColor clearColor]; progressButton.round = isRound; // 设置按钮的实际 frame if (isRound) { CGRect tmpFrame = frame; tmpFrame.origin.y = frame.origin.y - (frame.size.width - frame.size.height) * 0.5; tmpFrame.size.height = frame.size.width; progressButton.frame = tmpFrame; } else { progressButton.frame = frame; } // 设置显示的标题和颜色 [progressButton setTitle:title forState:UIControlStateNormal]; [progressButton setTitleColor:(textColor ? : [UIColor blackColor]) forState:UIControlStateNormal]; return progressButton; } /// 绘制进度条 - (void)drawRect:(CGRect)rect { // 设置按钮圆角 self.layer.masksToBounds = YES; self.layer.cornerRadius = rect.size.height * 0.5; // 绘制按钮的背景颜色 UIBezierPath *path = [UIBezierPath bezierPathWithRect:rect]; [self.backColor set]; [path fill]; // 设置进度终止时显示的内容 if (self.stopTitle) { // 设置下载完成后的标题 [self setTitle:self.stopTitle forState:UIControlStateNormal]; return; } if (self.progress <= 0) { return; } // 清除按钮背景图片 [self setBackgroundImage:nil forState:UIControlStateNormal]; // 设置进度值 [self setTitle:[NSString stringWithFormat:@"%.2f%%", self.progress * 100] forState:UIControlStateNormal]; if (self.isRound) { CGPoint center = CGPointMake(rect.size.height * 0.5, rect.size.height * 0.5); CGFloat radius = (rect.size.height - self.lineWidth) * 0.5; CGFloat startA = - M_PI_2; CGFloat endA = startA + self.progress * 2 * M_PI; // 绘制进度条背景 path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:2 * M_PI clockwise:YES]; [[[UIColor lightGrayColor] colorWithAlphaComponent:0.5] set]; path.lineWidth = self.lineWidth; [path stroke]; // 绘制进度条 path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES]; path.lineWidth = self.lineWidth; path.lineCapStyle = kCGLineCapRound; [self.lineColor set]; [path stroke]; } else { CGFloat w = self.progress * rect.size.width; CGFloat h = rect.size.height; // 绘制进度条背景 path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, rect.size.width, rect.size.height)]; [[[UIColor lightGrayColor] colorWithAlphaComponent:0.5] set]; [path fill]; // 绘制进度条 path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, w, h)]; [self.lineColor set]; [path fill]; } } /// 设置进度值 - (void)setProgress:(CGFloat)progress { _progress = progress; [self setNeedsDisplay]; } /// 设置进度终止状态标题 - (void)setStopTitle:(NSString *)stopTitle { _stopTitle = stopTitle; [self setNeedsDisplay]; } @end ViewController.m // 创建进度按钮 QProgressButton *progressButton = [QProgressButton q_progressButtonWithFrame:CGRectMake(100, 100, 100, 50) title:@"开始下载" lineWidth:10 lineColor:[UIColor blueColor] textColor:[UIColor redColor] backColor:[UIColor yellowColor] isRound:YES]; // 设置按钮点击事件 [progressButton addTarget:self action:@selector(progressUpdate:) forControlEvents:UIControlEventTouchUpInside]; // 将按钮添加到当前控件显示 [self.view addSubview:progressButton]; // 设置按钮的进度值 self.progressButton.progress = progress; // 设置按钮的进度终止标题,一旦设置了此标题进度条就会停止 self.progressButton.stopTitle = @"下载完成"; 效果

优秀的个人博客,低调大师

iOS - Quartz 2D 手势截屏绘制

1、绘制手势截屏 具体实现代码见 GitHub 源码 QExtension QTouchClipView.h @interface QTouchClipView : UIView /** * 创建手势截屏视图控件,获取截屏结果 * * @param view 截取图片的视图控件 * @param result 手势截屏结果 * * @return 手势截屏视图控件 */ + (instancetype)q_touchClipViewWithView:(UIView *)view clipResult:(void (^)(UIImage * _Nullable image))result; @end QTouchClipView.m @interface QTouchClipView () /// 截取图片的视图控件 @property (nonatomic, strong) UIView *baseView; /// 滑动手势结果 @property (nonatomic, copy) void (^resultBlock)(UIImage * _Nullable); /// 触摸开始结束点 @property (nonatomic, assign) CGPoint startP; @property (nonatomic, assign) CGPoint endP; @end @implementation QTouchClipView /// 创建手势截屏视图控件,获取截屏结果 + (instancetype)q_touchClipViewWithView:(UIView *)baseView clipResult:(void (^)(UIImage * _Nullable image))result { QTouchClipView *clipView = [[self alloc] initWithFrame:baseView.frame]; clipView.baseView = baseView; clipView.resultBlock = result; return clipView; } /// 初始化 - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5]; } return self; } /// 触摸开始 - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸起始点位置 CGPoint startPoint = [touches.anyObject locationInView:self]; self.startP = startPoint; } /// 触摸移动 - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 获取触摸点位置 CGPoint touchPoint = [touches.anyObject locationInView:self]; self.endP = touchPoint; // 刷新视图 [self setNeedsDisplay]; } /// 触摸结束 - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event { // 截取屏幕图片 UIGraphicsBeginImageContextWithOptions(self.baseView.bounds.size, NO, 0); CGContextRef ctx = UIGraphicsGetCurrentContext(); [self.baseView.layer renderInContext:ctx]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); // 切割图片 CGFloat x = self.startP.x; CGFloat y = self.startP.y; CGFloat w = self.endP.x - x; CGFloat h = self.endP.y - y; CGRect cutRect = CGRectMake(x * 2, y * 2, w * 2, h * 2); CGImageRef cgImage = CGImageCreateWithImageInRect(image.CGImage, cutRect); UIImage *newImage = [[UIImage alloc] initWithCGImage:cgImage]; CGImageRelease(cgImage); // 返回截取结果 if (self.resultBlock) { self.resultBlock(newImage); } // 移除截取视图控件 [self removeFromSuperview]; self.startP = CGPointZero; self.endP = CGPointZero; // 刷新视图 [self setNeedsDisplay]; } /// 触摸取消 - (void)touchesCancelled:(NSSet *)touches withEvent:(nullable UIEvent *)event { [self touchesEnded:touches withEvent:event]; } /// 绘制触摸区域 - (void)drawRect:(CGRect)rect { CGFloat x = self.startP.x; CGFloat y = self.startP.y; CGFloat w = self.endP.x - x; CGFloat h = self.endP.y - y; CGRect clipRect = CGRectMake(x, y, w, h); UIBezierPath *path = [UIBezierPath bezierPathWithRect:clipRect]; [[[UIColor whiteColor] colorWithAlphaComponent:0.2] setFill]; [path fill]; } @end ViewController.m // 创建手势截屏视图 QTouchClipView *touchClipView = [QTouchClipView q_touchClipViewWithView:self.imageView clipResult:^(UIImage * _Nullable image) { // 获取处理截屏结果 if (image) { UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil); } }]; // 添加手势截屏视图 [self.view addSubview:touchClipView]; 效果

优秀的个人博客,低调大师

Cairo 1.17.8 发布,计算机 2D 向量图形绘图库

Cairo 1.17.8 版本已发布,Cairo 是一个开源的图形库,为软件开发者提供了一个基于矢量图形、独立于设备的 API。Cairo 支持输出到一些不同的后端,后端支持包括 X11、Apple Quartz、Win32,以及 PNG、PDF、PostScript、DirectFB 和 SVG 等文件格式。 近年来 Cairo 的开发停滞不前,2018 年底推出了 Cairo 1.16 稳定版,然后就没有了消息。接着就是当前最新的Cairo 1.17.8 版本,Cairo 1.17.8 修复了各种错误,改进了对 macOS 和 Windows 的支持,支持渲染 COLRv1 字体,删除了 Autotools 构建系统以专注于 Meson。 此外,该版本还删除了 OpenGL/GLES 支持,因为该后端大约十年没有得到维护。 macOS 和 Windows 的支持改进涉及大量错误修复和构建更改,详情可查看更新公告。 cairo 使用 C 语言撰写的,但使用 cairo 时支持许多其他语言,包括有 C++、C#、Java、Python、Perl、Ruby、Scheme、Smalltalk 以及许多种语言,cairo 在 GPL 与 Mozilla Public License 两个开源许可证下发布。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册