標籤:
【上集劇情概要:上集我們主要剖析了原生的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開發之自動布局架構設計(二)