view hierarchy
@property(nullable, nonatomic,readonly) UIView *superview;
@property(nonatomic,readonly,copy) NSArray<__kindof UIView *> *subviews;
@property(nullable, nonatomic,readonly) UIWindow *window;
- (void)removeFromSuperview;
- (void)insertSubview:(UIView *)view atIndex:(NSInteger)index;
- (void)exchangeSubviewAtIndex:(NSInteger)index1 withSubviewAtIndex:(NSInteger)index2;
- (void)addSubview:(UIView *)view;
- (void)insertSubview:(UIView *)view belowSubview:(UIView *)siblingSubview;
- (void)insertSubview:(UIView *)view aboveSubview:(UIView *)siblingSubview;
- (void)bringSubviewToFront:(UIView *)view;
- (void)sendSubviewToBack:(UIView *)view;
- (BOOL)isDescendantOfView:(UIView *)view; // returns YES for self.
解释:
- view hierarchy本质是tree
- superview:view parent
- subviews:view children,添加subview会进行判断,nil不会添加,同一subview不会重复添加
- window:view所在view hierarchy(tree) root,即view controller.view.superview
view hierarchy图层
- superview位于下层,subviews位于上层
- 同一subviews,索引小的位于下层,索引大的位于上层,索引也称为view z-index或z-order
- (void)drawView
{
int width = self.view.bounds.size.width;
int halfHeight = self.view.bounds.size.height / 2;
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, halfHeight)];
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(40, 30, 200, 200)];
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(80, 60, 200, 200)];
UIView *view1_1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 80, 80)];
UIView *view1_2 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 80, 80)];
view.backgroundColor = [UIColor purpleColor];
view1.backgroundColor = [UIColor blueColor];
view2.backgroundColor = [UIColor orangeColor];
view1_1.backgroundColor = [UIColor redColor];
view1_2.backgroundColor = [UIColor cyanColor];
[self.view addSubview:view];
[view addSubview:view1];
[view addSubview:view2];
[view1 addSubview:view1_1];
[view1 addSubview:view1_2];
}
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, halfHeight, width, halfHeight)];
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(40, 30, 200, 200)];
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(80, 60, 200, 200)];
UIView *view1_1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 80, 80)];
UIView *view1_2 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 80, 80)];
view.backgroundColor = [UIColor brownColor];
view1.backgroundColor = [UIColor blueColor];
view2.backgroundColor = [UIColor orangeColor];
view1_1.backgroundColor = [UIColor redColor];
view1_2.backgroundColor = [UIColor cyanColor];
[self.view addSubview:view];
[view addSubview:view2];
[view addSubview:view1];
[view1 addSubview:view1_1];
[view1 addSubview:view1_2];
}
}
view hierarchy遍历
view hierarchy指以receiver为root view hierarchy,view hierarchy先根遍历
通常情况下,遍历子树按从左到右顺利遍历(subview index从小到大),用代码表示:
- (void)traverse
{
[self visit];
for(int i = 0; i < self.subviews.count; ++i)
{
UIView *view = [self.subviews objectAtIndex:i];
[view traverse];
}
}
特殊情况下,为了性能优化,遍历子树按从右到左顺利遍历(subview index从大到小),用代码表示:
- (void)traverse
{
[self visit];
for(int i = self.subviews.count - 1; i >= 0; --i)
{
UIView *view = [self.subviews objectAtIndex:i];
[view traverse];
}
}
view的draw(layout)为了性能优化,遍历子树按从右到左顺利遍历(subview index从大到小),先draw(layout)上层图层,然后draw(layout)下层图层,如果下层图层区域被上层图层不透明覆盖,则不必draw(layout)这些区域,极大提高了draw(layout)性能
view hierarchy crash
view hierarchy本质为tree,因此切不可形成闭环(循环),一旦形成闭环(循环),就破坏tree结构,先根遍历无穷递归,crash
- (void)circleCrash
{
UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(50, 50, 200, 200)];
UIView *view2 = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
UIView *subView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[self.view addSubview:view1];
[self.view addSubview:view2];
[view1 addSubview:subView];
[subView addSubview:self.view];
}
self.view->view1->subview->self.view形成闭环(循环)