美文网首页
iOS手势解锁和画板

iOS手势解锁和画板

作者: 恋空K | 来源:发表于2022-11-10 14:10 被阅读0次
    给UIView绘图的时候,一定要给它设一个背景颜色(包括clearColor,它也是一个颜色),不然绘图会很乱
    
    #import "LockView.h"
    
    @interface LockView ()
    /**
     *  当前选中的按钮
     */
    @property (nonatomic, strong) NSMutableArray *selectBtnArray;
    /**
     *  当前手指所在的点
     */
    @property (nonatomic, assign) CGPoint curP;
    
    @end
    
    
    @implementation LockView
    
    - (NSMutableArray *)selectBtnArray {
        if (_selectBtnArray == nil) {
            _selectBtnArray = [NSMutableArray array];
        }
        return _selectBtnArray;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        //添加按钮
        [self setUp];
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
        if ( self = [super initWithFrame:frame]) {
            //添加按钮
            [self setUp];
        }
        return self;
    }
    
    //添加按钮
    - (void)setUp {
        //创建按钮
        for (int i = 0; i <9; i++) {
            UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
            btn.userInteractionEnabled = NO;
            btn.tag = i;
            [btn setImage:[UIImage imageNamed:@"gesture_node_normal"] forState:UIControlStateNormal];
            [btn setImage:[UIImage imageNamed:@"gesture_node_highlighted"] forState:UIControlStateSelected];
            
            [self addSubview:btn];
        }
    }
    
    //给定一个集合,获取当前手指的点
    - (CGPoint)getCurPintWithTouches:(NSSet *)touches {
        //如果点在按钮上,让按钮成为选中状态
        //获取当前手指所在的点
        UITouch *touch = [touches anyObject];
        CGPoint curP = [touch locationInView:self];
        return curP;
    }
    
    /**
     *  给定一个点,判断点在不在按钮身上.
     *
     *  @param point 指定的点
     *
     *  @return 当前点所在的按钮,  该值有可能为nil. 点不在按钮身上为nil
     */
    - (UIButton *)btnRectContainsPoint:(CGPoint)point {
        for (UIButton *btn in self.subviews) {
            //判断一个点在不在指定的区域当中
            if (CGRectContainsPoint(btn.frame, point)) {
                return btn;
                break;
            }
        }
        return nil;
    }
    
    //开始点击
    - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        //如果点在按钮上,让按钮成为选中状态
        //获取当前手指所在的点
        CGPoint curP = [self getCurPintWithTouches:touches];
        UIButton *btn = [self btnRectContainsPoint:curP];
        if (btn && btn.selected == NO) {
            //保存当前选中的按钮
            [self.selectBtnArray addObject:btn];
            btn.selected = YES;
        }
    }
    
    - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        //如果点在按钮上,让按钮成为选中状态
        //获取当前手指所在的点
        CGPoint curP = [self getCurPintWithTouches:touches];
        //记录当前手指所在的点
        self.curP = curP;
        UIButton *btn = [self btnRectContainsPoint:curP];
        if (btn && btn.selected == NO) {
            //保存当前选中的按钮
            [self.selectBtnArray addObject:btn];
            btn.selected = YES;
        }
        //重绘
        [self setNeedsDisplay];
        
    }
    //当手指松开时调用
    - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
        NSMutableString *str = [NSMutableString string];
        //取消所有选中的按钮
        for (UIButton *btn in self.selectBtnArray) {
            btn.selected = NO;
            NSLog(@"%ld",btn.tag);
            [str appendFormat:@"%ld",btn.tag];
        }
        NSLog(@"%@",str);
        //清空数组
        [self.selectBtnArray removeAllObjects];
        
        //清空所有的连线
        //重绘
        [self setNeedsDisplay];
    }
    
    - (void)layoutSubviews {
        [super layoutSubviews];
        
        int column = 3;
        CGFloat btnWH = 74;
        CGFloat x = 0;
        CGFloat y = 0;
        
        CGFloat margin = (self.bounds.size.width - column * btnWH) / (column + 1);
    
        int curL = 0;
        int curR = 0;
        
        
        for (int i  = 0; i < self.subviews.count; i++) {
            
            curL = i % column;
            curR = i / column;
            
            x = margin + (btnWH + margin) * curL;
            y = margin + (btnWH + margin) * curR;
            
            UIButton *btn = self.subviews[i];
            btn.frame = CGRectMake(x, y, btnWH, btnWH);
            
        }
    
    }
    
    
    - (void)drawRect:(CGRect)rect {
        if (self.selectBtnArray.count) {
            //创建路径
            UIBezierPath *path = [UIBezierPath bezierPath];
            //设置路径的起点
            //遍历所有选中的按钮,如果是第一个按钮,按钮的中心成为路径的起点
            for (int i = 0; i < self.selectBtnArray.count; i++) {
                //取出选中的按钮
                UIButton *btn = self.selectBtnArray[i];
                //如果是第一个按钮,按钮的中心成为路径的起点
                if (i == 0) {
                    [path moveToPoint:btn.center];
                }else {
                    //不是第一个按钮, 添加一根线到按钮的中心
                    [path addLineToPoint:btn.center];
                }
            }
            //添加一根线到当前手指所在的点
            [path addLineToPoint:self.curP];
            [path setLineJoinStyle:kCGLineJoinRound];
            [path setLineWidth:10];
            [[UIColor redColor] set];
            //绘制路径
            [path stroke];
        }
    }
    
    @end
    
    手势解锁图
    一个path路径可以描述多根线,但是只有一个状态,每次调用- (void)drawRect:(CGRect)rect
    重绘的时候,都会清空之前所有的绘制的内容,也就是每次调用- (void)drawRect:(CGRect)rect
    的时候,都是往空白的view上绘制内容
    
    上面那个直接传size的方法,相当于下面那个方法,图片不透明,大小传的是0
    UIImagePickerController现实代理方法后,需要自己去dismiss这个控制器,这个dismiss可以是当前的
    控制器(自己)去dismiss,也可以是谁把它弹出来的,谁就可以去把它dismiss
    
    画板相关代码-----
    #import "ViewController.h"
    #import "DrawView.h"
    
    @interface ViewController ()<UINavigationControllerDelegate,UIImagePickerControllerDelegate>
    
    @property (weak, nonatomic) IBOutlet DrawView *drawView;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    //清屏
    - (IBAction)clear:(id)sender {
        [self.drawView clear];
    }
    
    //撤销
    - (IBAction)undo:(id)sender {
        [self.drawView undo];
    }
    
    //橡皮擦
    - (IBAction)erase:(id)sender {
        [self.drawView erase];
    }
    
    //照片
    - (IBAction)photo:(id)sender {
        //弹出系统相册,从中选择一张照片,把照片绘制到画板
        UIImagePickerController *pickVC = [[UIImagePickerController alloc] init];
        /**
         
         UIImagePickerControllerSourceTypePhotoLibrary,
         UIImagePickerControllerSourceTypeCamera,
         UIImagePickerControllerSourceTypeSavedPhotosAlbum
         */
        //设置照片的来源
        pickVC.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
        
        pickVC.delegate = self;
        
        [self presentViewController:pickVC animated:YES completion:nil];
    }
    
    
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {
        UIImage *image = info[UIImagePickerControllerOriginalImage];
        NSData *data = UIImageJPEGRepresentation(image, 1);
        
        [data writeToFile:@"/Users/xiaomage/Desktop/photo.jpg" atomically:YES];
        
        
        [self dismissViewControllerAnimated:YES completion:nil];
        
        self.drawView.image = image;
    }
    
    //保存
    - (IBAction)save:(id)sender {
        //对画板做截屏
        UIGraphicsBeginImageContext(self.drawView.bounds.size);
        
        //把View的layer的内容渲染到上下文当中
        CGContextRef ctx = UIGraphicsGetCurrentContext();
        [self.drawView.layer renderInContext:ctx];
        
        //从上下文当中生成一张图片
        UIImage *newImage =  UIGraphicsGetImageFromCurrentImageContext();
        
        //关闭上下文
        UIGraphicsEndImageContext();
        
        //把生成的图片保存到系统相册
        //保存完毕时调用的方法必须得是:image:didFinishSavingWithError:contextInfo:
        UIImageWriteToSavedPhotosAlbum(newImage, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
        
        
    }
    
    - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo {
        NSLog(@"保存完毕");
    }
    
    //设置颜色
    - (IBAction)setLineColor:(UIButton *)sender {
        [self.drawView setLineColor:sender.backgroundColor];
    }
    
    //设置线宽度
    - (IBAction)setLineWidth:(UISlider *)sender {
        [self.drawView setLineWidth:sender.value];
    }
    
    - (BOOL)prefersStatusBarHidden {
        return YES;
    }
    
    @end
    
    #import <UIKit/UIKit.h>
    
    @interface DrawView : UIView
    
    /**
     *  清屏
     */
    - (void)clear;
    
    /**
     *  撤销
     */
    - (void)undo;
    
    /**
     *  橡皮擦
     */
    - (void)erase;
    
    /**
     *  设置线的宽度
     *
     *  @param width 指定的宽度
     */
    - (void)setLineWidth:(CGFloat)width;
    
    /**
     *  置线的颜色
     *
     *  @param color 指定的颜色
     */
    - (void)setLineColor:(UIColor *)color;
    
    /**
     *  要绘制的图片
     */
    @property (nonatomic ,strong) UIImage *image;
    
    @end
    
    #import "DrawView.h"
    #import "MyBezierPath.h"
    
    @interface DrawView ()
    /**
     *  当前绘制的路径
     */
    @property (nonatomic, strong) UIBezierPath *path;
    
    /**
     *  保存当前绘制的所有路径 (一个路径只能对应一个状态)
     */
    @property (nonatomic, strong) NSMutableArray *pathArray;
    
    /**
     *  当前绘制的线宽
     */
    @property (nonatomic, assign) CGFloat width;
    
    /**
     *  当前绘制的线的颜色
     */
    @property (nonatomic, strong) UIColor *color;
    
    @end
    
    @implementation DrawView
    
    - (NSMutableArray *)pathArray {
        
        if (_pathArray == nil) {
            _pathArray = [NSMutableArray array];
        }
        return _pathArray;
    }
    
    - (void)awakeFromNib {
        [super awakeFromNib];
        //添加手势
        UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget: self action:@selector(pan:)];
        [self addGestureRecognizer:pan];
        
        self.width = 1;
        self.color = [UIColor blackColor];
    }
    
    - (void)setImage:(UIImage *)image {
        _image = image;
        [self.pathArray addObject:image];
        //重绘
        [self setNeedsDisplay];
    }
    
    
    /**
     *  清屏
     */
    - (void)clear {
        
        [self.pathArray removeAllObjects];
        //重绘
        [self setNeedsDisplay];
        
    }
    
    /**
     *  撤销
     */
    - (void)undo {
        
        [self.pathArray removeLastObject];
        //重绘
        [self setNeedsDisplay];
        
    }
    
    /**
     *  橡皮擦
     */
    - (void)erase {
        [self setLineColor:[UIColor whiteColor]];
    }
    
    /**
     *  设置线的宽度
     *
     *  @param width 指定的宽度
     */
    - (void)setLineWidth:(CGFloat)width {
        
        self.width = width;
    }
    
    /**
     *  置线的颜色
     *
     *  @param color 指定的颜色
     */
    - (void)setLineColor:(UIColor *)color {
        self.color = color;
    }
    
    
    - (void)pan:(UIPanGestureRecognizer *)pan {
        
        //获取当前手指所在的点
        CGPoint curP = [pan locationInView:self];
        
        //画线
        if (pan.state == UIGestureRecognizerStateBegan) {
            
            //创建路径
            MyBezierPath *path = [MyBezierPath bezierPath];
            path.lineWidth = self.width;
            path.lineJoinStyle = kCGLineJoinRound;
            path.lineCapStyle = kCGLineCapRound;
            //颜色必须得要在drawRect方法当中进行绘制
            path.lineColor = self.color;
          
            //当发现系统的类,没有办法满足我们要求时,继承系统类,添加属性我们自己的东西.
            
            self.path = path;
            
            //设置路径的起点
            [self.path moveToPoint:curP];
           
            //保存路径
            [self.pathArray addObject:path];
            
        }else if (pan.state == UIGestureRecognizerStateChanged) {
            
            //添加一根线到当前手指所在的点
            [self.path addLineToPoint:curP];
            
            //重绘
            [self setNeedsDisplay];
        }
        
    }
    
    
    - (void)drawRect:(CGRect)rect {
        //绘制所有的路径
        for (MyBezierPath *path in self.pathArray) {
            
            if ([path isKindOfClass:[UIImage class]]) {
                
                UIImage *image = (UIImage *)path;
                [image drawInRect:rect];
                
            }else {
                [path.lineColor set];
                [path stroke];
            }
        }
    }
    @end
    
    #import <UIKit/UIKit.h>
    
    @interface MyBezierPath : UIBezierPath
    /**
     *  当前路径的颜色
     */
    @property (nonatomic, strong) UIColor *lineColor;
    
    @end
    

    相关文章

      网友评论

          本文标题:iOS手势解锁和画板

          本文链接:https://www.haomeiwen.com/subject/dvcntdtx.html