• IOS开发之自动布局框架设计(二)


      【上集剧情概要:上集我们主要剖析了原生的NSLayoutConstraint实现自动布局的方式,我们知道是通过constraintWithItem这个初始化的方法来配备所需要的7个参数,然后通过addConstraint方法将布局添加进去,并且定义了

    NSLayoutAttribute,NSLayoutRelation这些枚举】

    如果我们自己设计一款布局框架可以怎么设计呢?

    1.封装原有的NSLayoutConstraint类,可以将代码的实现更加简洁化。例如:Masonry,SDAutoLayout。

    2.封装坐标布局,并且实现自有的布局方式,至于用什么方式展现给用户,可以自行天马行空,方便易用就行。

    3.使用CSS/XML等方式,将布局文件放到一个统一的文件里面,然后初始化的时候进行加载布局。

    4.开发一款软件,来实现拖拽好布局之后,自动生成代码,并且有面板可以设置微调当前的参数。

    5.还可以将UI动画封装到布局里面,以及控件的交互的封装。

    好吧,我们来看看如何封装好NSLayoutConstraint,其实它的核心代码是:

     1 NSLayoutConstraint *constaintTop = [NSLayoutConstraint
     2                                         constraintWithItem:self.tableView
     3                                         attribute:NSLayoutAttributeTop
     4                                         relatedBy:NSLayoutRelationEqual
     5                                         toItem:self.view
     6                                         attribute:NSLayoutAttributeTop
     7                                         multiplier:1.0
     8                                         constant:20];
     9     
    10     [_tableView addConstraint:constaintTop];

    那我们其实就是要封装这一层代码,并且实现更好地接口展现给用户。

    1.实现链式调用

    首先我们写一个最简单地实现UI布局的代码,功能:实现上下左右四个属性,使用链式调用。

    如果我们要实现链式调用,怎么实现呢?

    IOS中调用方法的实现使用的是【】,只有属性访问的时候才用点得方式,那么可以通过Setter方法吗?

    比如返回值我们设置为当前的view

    @property(nonatomic, readonly) UIView *leftSpace;
    
    -(UIView *)leftSpace
    {
        return self;
    }

    那后面的参数怎么传给它呢,所以它不能满足要求。

    橘子君又想到一个问题,使用Block呢,因为block作为属性的时候是可以用这种方式的:

    blockLeft(10);

    也是可以通过.语法来访问的比如:

    self.blockLeft(10);

    那我们怎么来实现连续的链式点语法的操作呢

    如果self.blockLeft(10);返回的是self的话,那就可以实现了:

    self.blockLeft(10).blockTop(10).blockRight(10).blockBottom(10);

    ok, 这样的话我们可以模拟实现一下这种链式调用的方式:

    #import <UIKit/UIKit.h>
    
    @interface UIView (GCFAdditions)
    
    @property(nonatomic, readonly) UIView *(^left)(NSInteger space);
    @property(nonatomic, readonly) UIView *(^right)(NSInteger space);
    @property(nonatomic, readonly) UIView *(^top)(NSInteger space);
    @property(nonatomic, readonly) UIView *(^bottom)(NSInteger space);
    
    @end

    首先简单模拟写了left,right,top,bottom四个block属性,返回值都为self

    #import "UIView+GCFAdditions.h"
    
    @implementation UIView (GCFAdditions)
    
    - (UIView *(^)(NSInteger space))left
    {
        return ^(NSInteger space) {
            //code
            if (space) {
                NSLog(@"%ld",(long)space);
            } else {
                NSLog(@"%ld",(long)space);
            }
            return self;
        };
    }
    
    - (UIView *(^)(NSInteger space))right
    {
        return ^(NSInteger space) {
            //code
            if (space) {
                NSLog(@"%ld",(long)space);
            } else {
                NSLog(@"%ld",(long)space);
            }
            
            return self;
        };
    }
    
    - (UIView *(^)(NSInteger space))top
    {
        return ^(NSInteger space) {
            //code
            if (space) {
                NSLog(@"%ld",(long)space);
            } else {
                NSLog(@"%ld",(long)space);
            }
            
            return self;
        };
    }
    
    - (UIView *(^)(NSInteger space))bottom
    {
        return ^(NSInteger space) {
            //code
            if (space) {
                NSLog(@"%ld",(long)space);
            } else {
                NSLog(@"%ld",(long)space);
            }
            
            return self;
        };
    }
    
    @end

    好,我们来仔细分析下上面的代码:

    首先在属性里面声明一个block,返回类型为UIView,保证下一步的调用,给了一个参数,测试用的。

    然后在实现里面,返回self,这时候就可以完成链式调用

    #define SCREEN_WIDTH   [UIScreen mainScreen].bounds.size.width
    #define SCREEN_HEIGHT  [UIScreen mainScreen].bounds.size.height
    
    #import "ViewController.h"
    #import "Masonry.h"
    #import "UIView+GCFAdditions.h"
    
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
    
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        self.tableView.left(50).right(50).top(50).bottom(50);
        
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    -(UITableView *)tableView
    {
        if (!_tableView) {
            _tableView=[[UITableView alloc]initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)];
            _tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
            _tableView.backgroundColor=[UIColor redColor];
            [self.view addSubview:_tableView];
        }
        return _tableView;
    }

    打印结果:

    2016-09-08 11:22:31.214 TestMansonry[298:16133] 50
    2016-09-08 11:22:31.215 TestMansonry[298:16133] 50
    2016-09-08 11:22:31.216 TestMansonry[298:16133] 50
    2016-09-08 11:22:31.216 TestMansonry[298:16133] 50

    2.实现最简单的布局

    上面我们实现了链式调用,那么我们如何运用它来实现布局呢,请看如下代码:

     NSLayoutConstraint *constaintRight = [NSLayoutConstraint
                                                 constraintWithItem:self
                                                 attribute:NSLayoutAttributeRight
                                                 relatedBy:NSLayoutRelationEqual
                                                 toItem:self.superview
                                                 attribute:NSLayoutAttributeRight
                                                 multiplier:1.0
                                                 constant:-space];
            
    [self.superview addConstraint:constaintRight];

    我们知道实现布局的核心代码是这一段,我们直接移到之前的分类里面就会实现这种效果

    - (UIView *(^)(NSInteger space))left
    {
        return ^(NSInteger space) {
            if (space) {
                NSLog(@"%ld",(long)space);
            } else {
                NSLog(@"%ld",(long)space);
            }
            
            NSLayoutConstraint *constaintLeft = [NSLayoutConstraint
                                                constraintWithItem:self
                                                attribute:NSLayoutAttributeLeft
                                                relatedBy:NSLayoutRelationEqual
                                                toItem:self.superview
                                                attribute:NSLayoutAttributeLeft
                                                multiplier:1.0
                                                constant:space];
            
            [self.superview addConstraint:constaintLeft];
            
            return self;
        };
    }

    在实现里面加入

    self.tableView.left(50).right(50).top(50).bottom(50);

    就可以实现上下左右各50的间距了,哈哈!

  • 相关阅读:
    UNIX网络编程——处理服务器中大量的TIME_WAIT
    UNIX网络编程——套接字选项(心跳检测、绑定地址复用)
    UNIX网络编程——TCP 滑动窗口协议
    [Training Video
    [Training Video
    [Training Video
    [Training Video
    [Training Video
    Use formatter to format your JAVA code
    右键菜单没有新建文本文件了,怎么办?
  • 原文地址:https://www.cnblogs.com/guchengfengyun/p/5852559.html
Copyright © 2020-2023  润新知