一、简介
SDAutoLayout是基于对frame进行设置的一直布局,被依赖的view布局要写在前面,不然有可能造成界面异常(或者布局后面添加[被依赖的view updateLayout]
,手动进行刷新)
二、原理
view是没有sd_layout
属性的,作者使用动态关联,扩展UIView
, 调用getter
方法时sd_layout
对象生成,此对象作为view对象的布局控制模块, 每次生成一个sd_layout对象,都把它加为super view
的autolayoutModelsArray
中,sd_layout
对象即SDAutoLyaout
的实例,SDAutoLayout
下设left, top, bottom, right
等对象负责具体的布局... 用文字解释不了,看个图:
可见作者的面向对象思想是相当牛B的。
当我们调用 view.sd_layout.leftSpaceToView(self.view, 20)
时,sd_layout
对象的leftSpaceToView
是个懒加载的block
, 我们这样是调用这个block, 这样在内部SDAutoLayout
对frame进行赋值,所以,SDAutoLayout
并不像其名字AutoLayout所示通过NSLayoutConstraint
来对view进行布局的,它是本质上通过修改视图的frame
来处理的。
继续:当调用[someView updateLayout]
的时候,我们顺着API找下去:
// UIView的Category中:
- (void)updateLayout
{
[self.superview layoutSubviews];
}
也就是说,当对一个view updateLayout的时候,它会调其父视图的layoutSubviews, 而当调用layoutSubviews时,SDAutoLayout使用方法交换,调用sd_layoutSubviews,我们可以看到交换方法的源代码:
+ (void)load
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray *selStringsArray = @[@"setText:"];
[selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) {
NSString *mySelString = [@"sd_" stringByAppendingString:selString];
Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
method_exchangeImplementations(originalMethod, myMethod);
}];
});
}
调用sd_layoutSubviews
// UIView的Category中:
- (void)sd_layoutSubviews
{
[self sd_layoutSubviews]; // 此处由于方法交换,调用[self layoutSubviews]
[self sd_layoutSubviewsHandle];
}
在sd_layoutSubviewsHandle
中,我们知道,看上面图中视图有一个autolayoutModelsArray
,它记录着其所有子视图用SDAutoLayout
布局的对象,并可以找到每一个子视图所关联着的SDAutoLayout
对象,所它来布局。上面谈到,在SDAutoLayout
中有left, top, bottom, right
等具体的对象,在这些对象中都有一个refView代表其所参照的视图,我们可以把它想像成链表,链表的上一个节点动了,其被参照的视图根据refView
找到前一个节点,从而作刷新。
三、实现
参考github上的Demo