亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > iOS > 正文

iOS簡單畫板開發案例分享

2020-07-26 03:23:09
字體:
來源:轉載
供稿:網友

最近在學習Quartz2D,學習了一個簡單畫板的實現,現在把實現過程記錄一下。

主要用到的點就是畫線,截屏,繪制圖片,選擇圖片,以及保存所有繪制的線。

首先在storyboard上布局好控件,設置約束等等,最后的效果是這樣:

自定義畫板DrawView,使用時可能是從xib中加載,也可能是手動創建,所以創建對象的方法需要實現兩個:

#import <UIKit/UIKit.h> @interface DrawView : UIView/** 線寬 */@property (nonatomic, assign) NSInteger lineWidth; /** 顏色 */@property(nonatomic, strong) UIColor *pathColor; /** 圖片 */@property(nonatomic, strong) UIImage *image; - (void)clear; - (void)undo;
- (void)awakeFromNib {     [self setUp];   } - (instancetype)initWithFrame:(CGRect)frame {     if (self == [super initWithFrame:frame]) {    [self setUp];  }  return self;}

setUp初始化方法,初始化時要做的事情就是給畫板添加拖動手勢,也可以將畫筆路徑的線寬在這里設置

//自定義初始化方法- (void)setUp {     //添加手勢  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];  [self addGestureRecognizer:pan];     //初始化時設置路徑線寬  _lineWidth = 2;   }

手指在畫板上移動時開始繪制線條,這里因為原生的UIBezierPath類沒有辦法設置路徑顏色,所以這里只能自定義Path類了   

#import <UIKit/UIKit.h> @interface DrawPath : UIBezierPath @property (nonatomic, strong) UIColor *pathColor; @end

手指移動時,繪制線條,路徑是自定義的Path類

@interface DrawView () @property(nonatomic, strong)DrawPath *path;/** 保存所有路徑的數組 */@property(nonatomic, strong) NSMutableArray *pathArr; @end //懶加載- (NSMutableArray *)pathArr {  if (_pathArr == nil) {         _pathArr = [NSMutableArray array];       }  return _pathArr;}
- (void)pan:(UIPanGestureRecognizer *)pan {     //獲取開始的觸摸點  CGPoint startP = [pan locationInView:self];     if (pan.state == UIGestureRecognizerStateBegan) {         //創建貝塞爾路徑    _path = [[DrawPath alloc]init];    _path.lineWidth = _lineWidth;    _path.pathColor = _pathColor;         //不能在手指抬起時將路徑添加到數組,因為在遍歷數組畫線時路徑還沒有被添加到數組里面    [_pathArr addObject:_path];         //設置起點    [_path moveToPoint:startP];       }     //連線  [_path addLineToPoint:startP];     //重繪,調用drawRect方法  [self setNeedsDisplay];   }

畫線實現drawRect方法,繪制線條或者圖片時,是把數組中的路徑全部畫出來

- (void)drawRect:(CGRect)rect {     //把所有路徑畫出來  for (DrawPath *path in self.pathArr) {         if ([path isKindOfClass:[UIImage class]]) {      //畫圖      UIImage *image = (UIImage *)path;      [image drawInRect:rect];    }else {      //畫線      [path.pathColor set];      [path stroke];    }  }   }

當把圖片添加到畫板時

- (void)setImage:(UIImage *)image {     _image = image;     [self.pathArr addObject:image];     //重繪調用drawRect才能在畫板上顯示圖片  [self setNeedsDisplay];}

還可以把直接更新路徑數組的操作封裝在畫板中

- (void)clear {  //清除  [self.pathArr removeAllObjects];     [self setNeedsDisplay];   } - (void)undo {  //撤銷  [self.pathArr removeLastObject];     [self setNeedsDisplay];}

控制器中:

@interface ViewController () <UIImagePickerControllerDelegate, UINavigationControllerDelegate>@property (weak, nonatomic) IBOutlet DrawView *drawView;@end

實現幾個按鈕對畫板的操作:

- (IBAction)clear:(id)sender {     //清屏  [_drawView clear];   } - (IBAction)undo:(id)sender {     //撤銷  [_drawView undo];   } - (IBAction)eraser:(id)sender {     //擦除 就是把路徑的顏色設置為畫板的背景色,假象  _drawView.pathColor = _drawView.backgroundColor;  _drawView.lineWidth = 20;   } - (IBAction)changeLineWidth:(UISlider *)sender {     //改變路徑線寬  _drawView.lineWidth = sender.value;   } - (IBAction)changeColor:(UIButton *)sender {        //改變路徑顏色  _drawView.pathColor = sender.backgroundColor;   } - (IBAction)pickPhoto:(id)sender {     //選擇照片  //彈出系統相冊  UIImagePickerController *picker = [[UIImagePickerController alloc]init];     //設置選擇控制器的來源 UIImagePickerControllerSourceTypeSavedPhotosAlbum:照片庫  picker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;     //設置代理  picker.delegate = self;     //modal出控制器  [self presentViewController:picker animated:YES completion:nil];   } - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {     //獲取選擇的圖片  UIImage *image = info[UIImagePickerControllerOriginalImage];     //創建一個處理圖片的view  ImageHandleView *handleView = [[ImageHandleView alloc]initWithFrame:self.drawView.bounds];     handleView.handleCompletionBlock = ^(UIImage *image){         _drawView.image = image;  };     [self.drawView addSubview:handleView];     //將圖片畫在畫板上  handleView.image = image;     //_drawView.image = image;     //dismiss  [self dismissViewControllerAnimated:YES completion:nil];  //NSLog(@"%@", info);   } - (IBAction)save:(id)sender {     [UIView animateWithDuration:0.15 animations:^{    //保存當前畫板上的內容         //開啟上下文    UIGraphicsBeginImageContextWithOptions(_drawView.bounds.size, NO, 0);         //獲取位圖上下文    CGContextRef ctx = UIGraphicsGetCurrentContext();         //把控件上的圖層渲染到上下文    [_drawView.layer renderInContext:ctx];         //獲取上下文中的圖片    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();         //關閉上下文    UIGraphicsEndImageContext();         //保存圖片到相冊    UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);         self.drawView.alpha = 0;  } completion:^(BOOL finished) {    [UIView animateWithDuration:0.15 animations:^{      self.drawView.alpha = 1;    }];  }];   } //保存成功后的方法必須是這個,不能隨便寫- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {     NSLog(@"保存成功");   }

從相冊選擇完圖片后把圖片顯示在畫板上了但是還沒有渲染到layer,這時候需要對圖片進行移動縮放旋轉這些操作的話,但是UIImage是不能拉伸旋轉這些操作的,UIImageView才可以,所以解決思路就是自定義一個view來專門處理對圖片的操作,在自定義view上放一個UIImageView,從相冊選擇圖片后獲取的image設置給UIImageView,這樣的自定義view上操作UIIamgeView。

#import <UIKit/UIKit.h> @interface ImageHandleView : UIView/** 圖片 */@property(nonatomic, strong) UIImage *image; /** block */@property(nonatomic, strong) void(^handleCompletionBlock)(UIImage *image);@end
#import "ImageHandleView.h" @interface ImageHandleView () <UIGestureRecognizerDelegate> /** image */@property(nonatomic, weak) UIImageView *imageView; @end @implementation ImageHandleView //防止圖片上的觸摸事件傳遞到畫板- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {     return _imageView;} - (UIImageView *)imageView {     if (_imageView == nil) {    UIImageView *imageV = [[UIImageView alloc]initWithFrame:self.bounds];         _imageView = imageV;         //設置imgaeview允許與用戶交互    _imageView.userInteractionEnabled = YES;         //添加手勢    [self setUpGestureRecognizer];         //把這個imageview添加到圖片處理的view上    [self addSubview:imageV];       }  return _imageView;} #pragma mark - 添加手勢- (void)setUpGestureRecognizer {     //平移手勢  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];  [_imageView addGestureRecognizer:pan];     //旋轉手勢  UIRotationGestureRecognizer *rotation = [[UIRotationGestureRecognizer alloc]initWithTarget:self action:@selector(rotation:)];  rotation.delegate = self;  [_imageView addGestureRecognizer:rotation];     //縮放手勢  UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc]initWithTarget:self action:@selector(pinch:)];  pinch.delegate = self;  [_imageView addGestureRecognizer:pinch];     //長按手勢  UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(longPress:)];  [_imageView addGestureRecognizer:longPress];   } #pragma mark - 處理平移手勢- (void)pan:(UIPanGestureRecognizer *)pan {     //獲取手指的偏移量  CGPoint tranp = [pan translationInView:self.imageView];     //設置imageview的形變  self.imageView.transform = CGAffineTransformTranslate(self.imageView.transform, tranp.x, tranp.y);     //復位  [pan setTranslation:CGPointZero inView:self.imageView];   } #pragma mark - 處理旋轉手勢- (void)rotation:(UIRotationGestureRecognizer *)rotation {     //設置imageview的形變  self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, rotation.rotation);     //復位  rotation.rotation = 0;   } #pragma mark - 處理縮放手勢- (void)pinch:(UIPinchGestureRecognizer *)pinch {     //設置imageview的形變  self.imageView.transform = CGAffineTransformScale(self.imageView.transform, pinch.scale, pinch.scale);     //復位  pinch.scale = 1;   } #pragma mark - 處理長按手勢- (void)longPress:(UILongPressGestureRecognizer *)longPress {     //圖片處理完成  if (longPress.state == UIGestureRecognizerStateBegan) {         //高亮效果    [UIView animateWithDuration:0.25 animations:^{      self.imageView.alpha = 0;    } completion:^(BOOL finished) {            [UIView animateWithDuration:0.25 animations:^{        self.imageView.alpha = 1;      } completion:^(BOOL finished) {                 //高亮時生成一張新的圖片        //開啟位圖上下文        UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0);                 //獲取位圖上下文        CGContextRef ctx = UIGraphicsGetCurrentContext();                 //把控件的圖層渲染到上下文        [self.layer renderInContext:ctx];                 //從上下文中獲取新的圖片        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();                 //關閉上下文        UIGraphicsEndImageContext();                 //調用block        if(_handleCompletionBlock) {          _handleCompletionBlock(image);        }                 //移除父控件        [self removeFromSuperview];               }];           }];            }   } #pragma mark - 手勢代理方法 <UIGestureRecognizerDelegate>- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {     //yes表示同時支持多個手勢  return YES;   } - (void)setImage:(UIImage *)image {     _image = image;     //把圖片展示到UIImageView上  self.imageView.image = image; } @end

需要注意的是,當長按將操作過的圖片繪制都畫板上生成一張新的圖片后,這時候需要把這個image設置給畫板drawView,但是這時候就必須要在專門處理圖片的view中去import畫板view,這樣耦合性太強。所以為了解耦,可以使用代理或者Block。我用了Block將剛剛生成的image先保存起來,在控制器中初始化imageHandleView之后再賦值給drawView。

最后保存畫板上的內容就是將畫板上的內容生成圖片保存到相冊即可。注意,保存完之后執行的方法必須是這個:

復制代碼 代碼如下:
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo;

最后效果圖是這樣的:

以上就是本文的全部內容,希望對大家學習iOS程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲美女av电影| 久久精品国产亚洲精品| 国产精品亚洲аv天堂网| 69av在线播放| 日韩中文字幕在线播放| 久久国产精品偷| 久久久久久国产免费| 亚洲国产一区二区三区四区| 久久视频中文字幕| 亚洲精品乱码久久久久久按摩观| 欧美激情啊啊啊| 欧美精品久久久久久久久| 92看片淫黄大片欧美看国产片| 狠狠躁夜夜躁人人爽天天天天97| 精品久久久久久国产91| 亚洲欧美一区二区精品久久久| 国产精品一区二区三区久久| 国产午夜精品视频免费不卡69堂| 欧美激情视频一区二区三区不卡| 欧美专区在线播放| 欧美性受xxx| 日韩av在线一区二区| 久久久国产在线视频| 亚洲欧洲av一区二区| 国产极品精品在线观看| 久久亚洲春色中文字幕| 国产原创欧美精品| 亚洲另类激情图| 亚洲日本欧美日韩高观看| 国产精品v日韩精品| 亚洲天堂精品在线| 国产精品久久久久久久久久三级| 成人精品一区二区三区电影免费| 欧美大肥婆大肥bbbbb| 国产91免费观看| 欧美xxxx综合视频| 日韩免费视频在线观看| 992tv在线成人免费观看| 欧美激情一区二区三区高清视频| 亚洲欧洲av一区二区| 伊人久久精品视频| 91亚洲精品一区| 亚洲伊人久久大香线蕉av| 91亚洲va在线va天堂va国| 欧美电影免费看| 久久久精品亚洲| 久久视频免费在线播放| 国产成人久久久| 精品视频久久久久久久| 国产精品久久久久91| 成人亚洲综合色就1024| 国内精品视频久久| 久久伊人免费视频| 91在线观看免费高清完整版在线观看| 国产视频观看一区| 欧美午夜激情小视频| 欧美激情一区二区三级高清视频| 亚洲网站在线看| 免费av一区二区| 久久精品最新地址| 亚洲一区中文字幕| 亚洲男子天堂网| 亚洲精品aⅴ中文字幕乱码| 亚洲视频一区二区三区| 18一19gay欧美视频网站| xxxx性欧美| 国产精品精品视频| 久久免费精品视频| 欧美亚洲第一页| 中文字幕日韩av综合精品| 日韩大胆人体377p| 亚洲色图色老头| 91中文在线观看| 国产97在线|日韩| 欧美最猛性xxxx| 亚洲欧美日韩国产精品| 91精品国产自产在线观看永久| 日韩av在线电影网| 日韩一区二区三区在线播放| 国产精品成久久久久三级| 午夜精品视频在线| 国产精品18久久久久久麻辣| 欧美性猛交丰臀xxxxx网站| 69久久夜色精品国产7777| 欧美亚洲视频在线看网址| 欧美成人亚洲成人| 欧美精品18videos性欧美| 91热精品视频| 久久精品成人一区二区三区| 久久久人成影片一区二区三区观看| 欧美成人小视频| 国产成人精品av在线| 国产精品丝袜久久久久久不卡| 亚洲成年人在线播放| 中文字幕国内精品| 久久中文字幕视频| 国产精品中文久久久久久久| 国产婷婷色综合av蜜臀av| 亚洲国产精品久久| 在线丨暗呦小u女国产精品| 亚洲3p在线观看| 亚洲男人的天堂网站| 欧美日韩亚洲视频| 日韩免费观看网站| 欧美老少做受xxxx高潮| 国产精品69精品一区二区三区| 欧美大片在线看免费观看| 久久久久久91香蕉国产| 欧美大肥婆大肥bbbbb| 最近中文字幕2019免费| 亚洲精品狠狠操| 俺去亚洲欧洲欧美日韩| 日本免费久久高清视频| 伊是香蕉大人久久| 国产日韩在线亚洲字幕中文| 亚洲欧美激情视频| 亚洲欧美日韩视频一区| 国产精品嫩草影院一区二区| 成人免费xxxxx在线观看| 欧美性猛交xxxx黑人猛交| 国产精品jizz在线观看麻豆| 亚洲精品不卡在线| 国产精品久久久久久久久久尿| 亚洲国产精品网站| 亚洲色图17p| 精品久久久久久中文字幕| 91综合免费在线| 国产精品色悠悠| 精品高清一区二区三区| 狠狠躁夜夜躁人人躁婷婷91| 国产精品视频免费观看www| 色狠狠久久aa北条麻妃| 国产日本欧美一区| 成人福利视频网| 国产精品免费福利| 97视频com| 国产精品久久久久久亚洲影视| 精品无人国产偷自产在线| 在线观看欧美日韩| 久久香蕉精品香蕉| 一本色道久久综合狠狠躁篇的优点| 亚洲最大成人网色| 亚洲国产精品va在看黑人| 成人国内精品久久久久一区| 欧美福利小视频| 欧美成人高清视频| 精品偷拍一区二区三区在线看| 91在线国产电影| 美日韩精品免费视频| 狠狠躁夜夜躁久久躁别揉| 亚洲欧美综合精品久久成人| 成人自拍性视频| 91在线免费看网站| 国产精品美女在线观看| 在线播放国产精品| 国产午夜精品全部视频在线播放| 国产精品久久99久久| 亚洲高清久久久久久| 91精品国产综合久久久久久久久| 欧美www视频在线观看| 亚州精品天堂中文字幕| 欧美日韩高清区| 亚洲精品小视频在线观看| 91在线视频导航|