-
Notifications
You must be signed in to change notification settings - Fork 1
Description
iOS8.0 之前 AutoresizingMask
AutoresizingMask:属于旧的布局方式, 主要思想是设置子视图跟随父视图的frame变化而变化
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
iOS8之后 AutoLayout: 自动布局方式
- 使用之前必须
translatesAutoresizingMaskIntoConstraints == false translatesAutoresizingMaskIntoConstraints属性是设置到底使用那种布局方式,默认是true,- 使用xib时view 默认是false
主要思想是相对控件的约束:
+(instancetype)constraintWithItem:(id)view1 attribute:(NSLayoutAttribute)attr1 relatedBy:(NSLayoutRelation)relation toItem:(nullable id)view2 attribute:(NSLayoutAttribute)attr2 multiplier:(CGFloat)multiplier constant:(CGFloat)c;
-
view1 的某一个约束 = view2的某一个约束 X 多少倍 + 常量
-
relation: 有 <=/=/>= 三种关系, 自动布局时优先使用 = 关系(绝对关系,不满足时再用其他的关系, 因为是相对布局)平时宽度和高度不应该使用 “=” ,除非宽高有固定的要求
-
使用 eqal 时可能引发的问题:
(1.)根据内容决定宽度的视图,当内容改变时,外观尺寸无法做出正确的改变
(2.)过长的文字无法显示
(3.)约束之间冲突,无法显示正确的布局 -
NSLayoutAttributeLeft和NSLayoutAttributeLeading的区别,
left表示的就是左边,而Leading时根据文字习惯区分,表示的是从文字开始的方向,阿拉伯语中表示右边 -
Auto Layout 添加约束的规则
(1.)同层级视图添加到共同的父视图
(2.)不同层级试图添加到他们最近的共同父视图
(3.)有层级关系的添加到,添加到层次较高的父试视图
如果你还在使用iOS8.0 的constraintWithItem 纯代码来适配iPhone X ,底部和顶部的适配因该是这样做
// 底部
[NSLayoutConstraint constraintWithItem:testButton attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeBottomMargin multiplier:1.0 constant:0].active = YES;
// 顶部
[NSLayoutConstraint constraintWithItem:testButton1 attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeTopMargin multiplier:1.0 constant:0].active = true;
iOS 9.0 之后 出现了 NSLayoutAnchor 布局和 UILayoutGuide
官方解释
A rectangular area that can interact with Auto Layout.(可以与自动布局交互的矩形区域)UILayoutGuide占位视图简化布局效果时的工作量,没有任何内容的UIView只定义一个矩形区域,在自动布局体系中起到占位作用。例如,若干个宽度不等的控件,要求横向排列它们,并且间距相等。此时必须使用占位视图作为间距,否则需要大量计算,十分麻烦
使用 NSLayoutAnchor 适配iPhone X
// 底部,
[testButton.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:0].active = true;
// 顶部
[testButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:0].active = true;
layoutMarginsGuide
- view 有两个与内边距有关的属性,
layoutMargins是内边距的大小layoutMarginsGuide是内边界,默认的内边距大小是8个点layoutMarginsGuide布局子控件的时候有时候会有问题,没有居中显示,一般情况下使用UILayoutGuide来布局
使用场景
- 场景一:当作容器使用,需求是两个控件组合后居中显示
- (void)containerCenter {
// 创建layoutGuide
UILayoutGuide *containerGuide = [[UILayoutGuide alloc] init];
[self.view addLayoutGuide:containerGuide];
UILabel *label = [[UILabel alloc] init];
label.text = @"居中显示";
label.backgroundColor = [UIColor purpleColor];
label.textColor = [UIColor yellowColor];
[self.view addSubview:label];
// view1
UIView *view1 = [[UIView alloc] init];
view1.backgroundColor = [UIColor cyanColor];
[self.view addSubview:view1];
// view2
UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor redColor];
[self.view addSubview:view2];
// 设置view 为layout布局
label.translatesAutoresizingMaskIntoConstraints = NO;
view1.translatesAutoresizingMaskIntoConstraints = NO;
view2.translatesAutoresizingMaskIntoConstraints = NO;
// 设置containerGuide约束
[containerGuide.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;
[containerGuide.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
[containerGuide.heightAnchor constraintEqualToConstant:5].active = YES;
// 设置view1约束
[view1.widthAnchor constraintEqualToConstant:80].active = YES;
[view1.heightAnchor constraintEqualToConstant:60].active = YES;
[view1.leftAnchor constraintEqualToAnchor:containerGuide.leftAnchor].active = YES;
[view1.centerYAnchor constraintEqualToAnchor:containerGuide.centerYAnchor].active = YES;
// 设置label约束
[label.leftAnchor constraintEqualToAnchor:view1.rightAnchor constant:10].active = YES;
[label.centerYAnchor constraintEqualToAnchor:containerGuide.centerYAnchor].active = YES;
// 设置view2约束
[view2.widthAnchor constraintEqualToConstant:120].active = YES;
[view2.heightAnchor constraintEqualToConstant:40].active = YES;
[view2.leftAnchor constraintEqualToAnchor:label.rightAnchor constant:20].active = YES;
[view2.rightAnchor constraintEqualToAnchor:containerGuide.rightAnchor].active = YES;
[view2.centerYAnchor constraintEqualToAnchor:containerGuide.centerYAnchor].active = YES;
}
- 场景二:当作占位图,空间之间等间距
- (void)spaceTest {
// 创建layoutGuide
UILayoutGuide *space1 = [[UILayoutGuide alloc] init];
[self.view addLayoutGuide:space1];
UILayoutGuide *space2 = [[UILayoutGuide alloc] init];
[self.view addLayoutGuide:space2];
UILayoutGuide *space3 = [[UILayoutGuide alloc] init];
[self.view addLayoutGuide:space3];
UILayoutGuide *space4 = [[UILayoutGuide alloc] init];
[self.view addLayoutGuide:space4];
UIView *view1 = [[UIView alloc] init];
view1.backgroundColor = [UIColor cyanColor];
[self.view addSubview:view1];
UIView *view2 = [[UIView alloc] init];
view2.backgroundColor = [UIColor redColor];
[self.view addSubview:view2];
UILabel *label = [[UILabel alloc] init];
label.text = @"1111";
label.backgroundColor = [UIColor purpleColor];
label.textColor = [UIColor yellowColor];
[self.view addSubview:label];
view1.translatesAutoresizingMaskIntoConstraints = NO;
view2.translatesAutoresizingMaskIntoConstraints = NO;
label.translatesAutoresizingMaskIntoConstraints = NO;
[space1.widthAnchor constraintEqualToConstant:40].active = YES;
[space2.widthAnchor constraintEqualToAnchor:space1.widthAnchor].active = YES;
[space3.widthAnchor constraintEqualToAnchor:space1.widthAnchor].active = YES;
[space1.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:-100].active = YES;
[space1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES;
[view1.heightAnchor constraintEqualToConstant:60].active = YES;
[view1.widthAnchor constraintEqualToConstant:30].active = YES;
[view2.heightAnchor constraintEqualToConstant:90].active = YES;
[view2.widthAnchor constraintEqualToConstant:30].active = YES;
[view1.centerYAnchor constraintEqualToAnchor:space1.centerYAnchor].active = YES;
[view2.centerYAnchor constraintEqualToAnchor:space1.centerYAnchor].active = YES;
[label.centerYAnchor constraintEqualToAnchor:space1.centerYAnchor].active = YES;
[view1.leadingAnchor constraintEqualToAnchor:space1.trailingAnchor].active = YES;
[space2.leadingAnchor constraintEqualToAnchor:view1.trailingAnchor].active = YES;
[view2.leadingAnchor constraintEqualToAnchor:space2.trailingAnchor].active = YES;
[space3.leadingAnchor constraintEqualToAnchor:view2.trailingAnchor].active = YES;
[label.leadingAnchor constraintEqualToAnchor:space3.trailingAnchor].active = YES;
}
topLayoutGuide 和 bottomLayoutGuide
两者都是ViewController 的属性,iOS7 就已经可以用了
官方注释如下
These objects may be used as layout items in the NSLayoutConstraint API @property(nonatomic,readonly,strong) id<UILayoutSupport> topLayoutGuide API_DEPRECATED("Use view.safeAreaLayoutGuide.topAnchor instead of topLayoutGuide.bottomAnchor", ios(7.0,11.0), tvos(7.0,11.0)); @property(nonatomic,readonly,strong) id<UILayoutSupport> bottomLayoutGuide API_DEPRECATED("Use view.safeAreaLayoutGuide.bottomAnchor instead of bottomLayoutGuide.topAnchor", ios(7.0,11.0), tvos(7.0,11.0));
iOS 11 之后以上两个属性过期,使用 self.view.safeAreaLayoutGuide.topAnchor 来调用
使用此属性可以方便的来适配iPhoneX
官方文档及Demo
NSLayoutGuide
updateConstraintsIfNeeded
立即触发更新约束,系统会自动调用,如果修改了约束之后也可以手动调用
setNeedsUpdateConstraints
标记需要更新约束,但不会立即更新
updateConstraints
一般是自定义view 重写此方法建立constraints,在最后调用 [super updateConstraints];
setNeedsLayout
标记当前布局需要更新,但不会立即更新当前布局
平时使用时需要两种配合使用才会调用 updateConstraints
// 标记需要更新
[self setNeedsUpdateConstraints];
// 立即更新
[self updateConstraintsIfNeeded];
// 立即布局
[UIView animateWithDuration:0.5 animations:^{
[self layoutIfNeeded];
}];
layoutIfNeeded
强制进行布局,立即更新布局,会调用再次调用 layoutSubviews
edgesForExtendedLayout
typedef NS_OPTIONS(NSUInteger, UIRectEdge) {
UIRectEdgeNone = 0,
UIRectEdgeTop = 1 << 0,
UIRectEdgeLeft = 1 << 1,
UIRectEdgeBottom = 1 << 2,
UIRectEdgeRight = 1 << 3,
UIRectEdgeAll = UIRectEdgeTop | UIRectEdgeLeft | UIRectEdgeBottom | UIRectEdgeRight
} NS_ENUM_AVAILABLE_IOS(7_0);
返回值是一个枚举类型,指定布局时四个边的位置,默认是整个屏幕,UIRectEdgeNone时如果有NavgationBar 或者 TableBar会自动适应,也可以指定