美文网首页
iOS开发必备干货

iOS开发必备干货

作者: Mr_Watson | 来源:发表于2018-05-18 10:25 被阅读0次

    把自己以往做的项目中的一些小功能抠出来写在这里,供大家使用,会一直持续更新

    UITextView自适应高度

    1.KVO

    //静态变量的地址可以保证context的独一无二
    static void * abc = &abc;
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(20, 20, 200, 35)];
        [self.view addSubview:textView];
        textView.layer.borderColor = [UIColor lightGrayColor].CGColor;
        textView.layer.borderWidth = 1;
        textView.layer.cornerRadius = 5;
        textView.font = [UIFont systemFontOfSize:20];
    
        //为textView添加一个观察者,来观察他的contentSize属性的变化
        //context:上下文. 对某一个属性或者方法之类的 跨方法使用时的唯一标识
        [textView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:abc];
    }
    
    //当前对象 如果观察到了 某些变化时就会触发下方的方法
    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        //使用context作为判断依据  尽量不要使用keyPath
        if (context == abc) {
            NSLog(@"%@", change);
            CGSize size = [change[@"new"] CGSizeValue];
            UITextView *textView = (UITextView *)object;
            CGRect frame = textView.frame;
            //限制高度 根据打印,5行时 高度136 高度未变化也不更新布局
            if (size.height > 140 || size.height == frame.size.height) {
                return;
            }
            frame.size.height = size.height;
            textView.frame = frame;
        } else {
            [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        }
    }
    

    2.sizeThatFits:

    //文本更改时触发高度自适应
    - (void)textViewDidChange:(UITextView *)textView {    
    
        //根据文本调整textView的高度
        CGSize sizeToFit = [textView sizeThatFits:CGSizeMake(textView.frame.size.width-16, MAXFLOAT)];
        
        //判断高度是否变化,未变化不重新布局
        if (sizeToFit.height != textView.frame.size.height) {
            textView.frame = CGRectMake(textView.frame.origin.x, textView.frame.origin.y, textView.frame.size.width, sizeToFit.height);
        }
    }
    

    实现二维码扫描的空心遮罩

    cropRect为扫描二维码框的Rect

    1.CoreGraphics -> CGPath

    - (void)setCropRect:(CGRect)cropRect{
        CAShapeLayer *cropLayer = [[CAShapeLayer alloc] init];    
        CGMutablePathRef path = CGPathCreateMutable();
        CGPathAddRect(path, nil, cropRect);
        CGPathAddRect(path, nil, self.view.bounds);
        
        [cropLayer setFillRule:kCAFillRuleEvenOdd];//生成空心遮罩
        [cropLayer setPath:path];
        CFRelease(path);//CF对象记得手动释放
        [cropLayer setFillColor:[UIColor blackColor].CGColor];
        [cropLayer setOpacity:0.3];
        
        [cropLayer setNeedsDisplay];
        
        [self.view.layer addSublayer:cropLayer];
    }
    

    2.UIKit -> UIBezierPath

    - (void)setCropRect:(CGRect)cropRect{
        CAShapeLayer *cropLayer = [[CAShapeLayer alloc] init];
        
        UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.view.bounds cornerRadius:0];
        UIBezierPath *rectPath = [UIBezierPath bezierPathWithRect:cropRect];
        [path appendPath:rectPath];
    
        [cropLayer setFillRule:kCAFillRuleEvenOdd];//生成空心遮罩
        [cropLayer setPath:path.CGPath];
        [cropLayer setFillColor:[UIColor blackColor].CGColor];
        [cropLayer setOpacity:0.3];
        
        [cropLayer setNeedsDisplay];
        
        [self.view.layer addSublayer:cropLayer];
    }
    
    空心遮罩.PNG

    UIImageView的手势缩放

    通过UIScrollViewDelegate中的代理方法来对UIImageView实现简单的缩放功能
    附加手势实现:
    缩放比例为1(未进行缩放)时,放大倍数
    缩放比例大于1(进行过缩放)时,还原倍数

    _scrollView.minimumZoomScale = 1.0; // 最小缩放比例 
    _scrollView.maximumZoomScale = 6.0; // 最大缩放比例
    
    _imageView.userInteractionEnabled = YES; // 记得打开UIImageView的用户交互,否则手势无法触发
    
    #pragma mark - UIScrollView Delegate
    - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
    {
        return _imageView; // 指定需要缩放的view,否则无法实现缩放功能(可为多个view)
    }
    
    #pragma mark - GestureRecogizer Method
    - (void)addGestureRecognizer {
        // 双击的 Recognizer
        UITapGestureRecognizer* doubleRecognizer;
        doubleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTap:)];
        doubleRecognizer.numberOfTapsRequired = 2; // 双击
        // _imageView添加双击手势
        [_imageView addGestureRecognizer:doubleRecognizer];
    }
    
    -(void)doubleTap:(UITapGestureRecognizer*)recognizer
    {
        if (_scrollView.zoomScale > 1.0) {//放大过 --> 还原大小
            [UIView animateWithDuration:.2 animations:^{
                _scrollView.zoomScale = 1.0;
            }];
        } else {//未放大 --> 放大2倍
            [UIView animateWithDuration:.2 animations:^{
                _scrollView.zoomScale = 2.0;
            }];
        }
    }
    
    手势缩放.gif

    JSON与JSON字符串相互转换

    1.JSON转JSON字符串
    思路:NSDictionary/NSArray -> NSData -> NSString

    方法:

    + (NSString *)parseJSONToJSONString:(id)JSON {
    
        NSError *error;
    
        NSData *JSONData = [NSJSONSerialization dataWithJSONObject:JSON options:NSJSONWritingPrettyPrinted error:&error];
    
        NSString *JSONString = [[NSString alloc] initWithData:JSONData encoding:NSUTF8StringEncoding];
    
        return JSONString;
    
    }
    

    2.JSON字符串转JSON
    思路:NSString -> NSData -> NSDictionary/NSArray

    方法:

    + (id)parseJSONStringToJSON:(NSString *)JSONString {
    
        NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
    
        id JSON = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableLeaves error:nil];
    
        return JSON;
    }
    

    备注:
    1.NSJSONReadingOptions

    typedef NS_OPTIONS(NSUInteger, NSJSONReadingOptions) {
        NSJSONReadingMutableContainers = (1UL << 0),
        NSJSONReadingMutableLeaves = (1UL << 1),
        NSJSONReadingAllowFragments = (1UL << 2)
    } API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
    
    NSJSONReadingMutableContainers // 返回可变容器,NSMutableDictionary或NSMutableArray
    NSJSONReadingMutableLeaves // 不仅返回的最外层是可变的, 内部的子数值或字典也是可变对象
    NSJSONReadingAllowFragments // 返回允许JSON字符串最外层既不是NSArray也不是NSDictionary,但必须是有效的JSON Fragment.
    

    2.NSJSONWritingOptions

    typedef NS_OPTIONS(NSUInteger, NSJSONWritingOptions) {
        NSJSONWritingPrettyPrinted = (1UL << 0),
        NSJSONWritingSortedKeys API_AVAILABLE(macos(10.13), ios(11.0), watchos(4.0), tvos(11.0)) = (1UL << 1)
    } API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
    
    NSJSONWritingPrettyPrinted // 是将生成的json数据格式化输出,这样可读性高,不设置则输出的json字符串就是一整行
    NSJSONWritingSortedKeys // 输出的json字符串就是一整行 仅支持iOS11以上
    

    利用UIBezierPath绘制三角形

    - (void)drawRect:(CGRect)rect {
        
        //绘制路径
        UIBezierPath *path = [UIBezierPath bezierPath];
        
        //设置颜色
        [self.triangleColor set];
        
        //-------------绘制三角形------------
        //
        //                 B
        //                /\
        //               /  \
        //              /    \
        //             /__  __\
        //            A        C
        //
        
        //设置起点 A
        [path moveToPoint:CGPointMake(0, rect.size.height)];
        
        //添加一根线到某个点 B
        [path addLineToPoint:CGPointMake(rect.size.width * 0.5, 0)];
        
        //添加一根线到某个点 C
        [path addLineToPoint:CGPointMake(rect.size.width, rect.size.height)];
        
        //关闭路径
        [path closePath];
        
        //填充(会把颜色填充进去)
        [path fill];
    }
    

    验证码倒计时

    - (void)theCountdown
    {
        __block int timeout = 60;
        __weak __typeof(self)weakSelf = self;
    
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        //dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, <#intervalInSeconds#> * NSEC_PER_SEC, <#leewayInSeconds#> * NSEC_PER_SEC); intervalInSeconds(倒计时间隔),leeway(期望的延迟时间)
        dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
        //dispatch_source_set_event_handler(dispatch_source_t source, dispatch_block_t _Nullable handler); dispatch_block_t 为block
        dispatch_source_set_event_handler(timer, ^{
            //因为^{}为block,有循环引用问题,所以需要弱引用倒计时按钮
            if(timeout<=0){
                //倒计时结束,关闭
                dispatch_source_cancel(_timer);
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf.codeBtn setTitle:@"发送验证码" forState:0];
                    [weakSelf.codeBtn setTitleColor:[UIColor whiteColor] forState:0];
                    [weakSelf.codeBtn setUserInteractionEnabled:YES];
                });
            }else{
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf.codeBtn setTitle:[NSString stringWithFormat:@"%ds",timeout] forState:0];
                    [weakSelf.codeBtn setTitleColor:[UIColor whiteColor] forState:0];
                    [weakSelf.codeBtn setUserInteractionEnabled:NO];
                });
                timeout--;
            }
        });
        dispatch_resume(timer);
    }
    
    
    验证码倒计时.gif

    下拉放大

    #define headerHeight 200
    @property (nonatomic, strong) UIImageView *iconIV;
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.iconIV = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"scrollViewImage"]];
        self.iconIV.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, headerHeight);
        //放大时不改变宽高比例
        self.iconIV.contentMode = UIViewContentModeScaleAspectFill;
        self.iconIV.clipsToBounds = YES;
        /*
         头部视图 x y width 都是不能设置的 而图片要随着下拉 调整y轴 所以图片不能直接作为头部视图
         可以把图片放到一个view里 view作为头部 而且view不能剪切子视图
         */
        UIView *headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, headerHeight)];
        headerView.clipsToBounds = NO;//不剪切子视图超出部分!!!
        [headerView addSubview:self.iconIV];
        self.tableView.tableHeaderView = headerView;
        
        [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"];
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
        return 10;
    }
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        cell.textLabel.text = @"这是个下拉放大的Demo!";
        return cell;
    }
    
    - (void)scrollViewDidScroll:(UIScrollView *)scrollView{
        CGPoint offset = scrollView.contentOffset;
        NSLog(@"%f", offset.y);
        //根据打印值:向上移动 正数 向下移动 负数
        CGFloat height = headerHeight - offset.y;
        self.iconIV.frame = CGRectMake(0, offset.y, self.view.frame.size.width, height);
    }
    
    下拉放大.gif

    相关文章

      网友评论

          本文标题:iOS开发必备干货

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