首页 > 代码库 > IOS开发之自动布局框架设计(二)
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] 502016-09-08 11:22:31.215 TestMansonry[298:16133] 502016-09-08 11:22:31.216 TestMansonry[298:16133] 502016-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的间距了,哈哈!
IOS开发之自动布局框架设计(二)