其间有多少个主旨的布局方法要求精通,再度调节和测试的时候就足以因而 lldb 来调节了

UIView是我们日常接纳的2个主干控件,个中有几个中央的布局方法需求驾驭。

刚起始运用 Autolayout
碰着上面包车型地铁警告人简单令人消沉,日常无所适从而丢弃了使用 Autolayout。

  • layoutSubViews:
    添加子视图常重写这一个办法,那些办法是用来再一次布局子视图的,常用来对子视图布局,或许在别的办法中调用以达到重新布局的效益。

  • setNeedsLayout
    告诉页面要求立异,可是不会登时开始更新,执行后会马上调用layoutSubviews

  • layoutIfNeeded
    告知页面布局马上更新,所以一般都会和setNeedsLayout一同利用。假若期望马上生成新的frame内需调用此办法,利用那一点一般布局动画能够在更新布局后平昔运用那么些点子让动画生效。

  • setNeedsUpdateConstraints
    告诉需求更新约束,不过不会应声起先

  • updateConstraintsIfNeeded
    报告立即更新约束

  • updateConstraints
    系统更新约束

Unable to simultaneously satisfy constraints.Probably at least one of the constraints in the following list is one you don't want.Try this: look at each constraint and try to figure out which you don't expect; find the code that added the unwanted constraint or constraints and fix it.(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)(...........)Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

触发layoutSubviews的时机

  • init格局初步化不会接触layoutSubviews,不过是用initWithFrame
    举办早先化时,当rect的值不为CGRectZero时,会触发。
  • addSubview方法会触发layoutSubviews
  • 设置viewFrame会触发layoutSubviews,前提是frame的值设置内外爆发了变更。
  • 滚动二个UIScrollView会触发layoutSubviews
  • 旋转Screen会触发父UIView上的layoutSubviews
  • 变动贰个UIView大小的时候也会触发父UIView上的layoutSubviews

小心:layoutSubViews在drawRect此前调用。

正如输出中所述,Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger,将来牵线下采纳
UIViewAlertForUnsatisfiableConstraints 的调剂方法。

UIViewAlertForUnsatisfiableConstraints 添加 symbolic breakpoint

  • 开拓断点导航
  • 点击左下角的+按钮
  • 选择Add Symbolic Breakpoint
  • 在Symbol添加UIViewAlertForUnsatisfiableConstraints

图片 1image.png

重新调节和测试的时候就足以因而 lldb 来调节了,然并卵,借使你不通晓 lldb 的话。

因而交给你1个小技巧,添加

po [[UIWindow keyWindow] _autolayoutTrace] // OC项目expr -l objc++ -O -- [[UIWindow keyWindow] _autolayoutTrace] // Swift项目

图片 2image.png

如此就足以一向看出输出:

 po [[UIWindow keyWindow] _autolayoutTrace]UIWindow:0x7f9481c93360| •UIView:0x7f9481c9d680| | *UIView:0x7f9481c9d990- AMBIGUOUS LAYOUT for UIView:0x7f9481c9d990.minX{id: 13}, UIView:0x7f9481c9d990.minY{id: 16}| | *_UILayoutGuide:0x7f9481c9e160- AMBIGUOUS LAYOUT for _UILayoutGuide:0x7f9481c9e160.minY{id: 17}| | *_UILayoutGuide:0x7f9481c9ebb0- AMBIGUOUS LAYOUT for _UILayoutGuide:0x7f9481c9ebb0.minY{id: 27}

里头 AMBIGUOUS
相关的视图正是约束有题指标。0x7f9481c9d990正是有毛病视图的首地址。

理所当然尤为的调节需求 lldb 的命令。比如,打字与印刷视图对象

 po 0x7f9481c9d990<UIView: 0x7f9481c9d990; frame = (0 0; 768 359); autoresize = RM+BM; layer = <CALayer: 0x7fc82d338960>>

变动颜色:

 expr (0x174197010).backgroundColor = [UIColor redColor](UICachedDeviceRGBColor *) $4 = 0x0000000174469cc0

结余的就是去代码中找到那些视图,然后修改其约束了。

UIView 是大家常常使用的3个着力控件,当中有多少个主导的布局方法需求了然。

  • layoutSubViews:

View 及其富有子视图的 frame 爆发变动的时候,会调用
layoutSubviews,所以在急需更新 frame
来再度定位或改动大小时重载它。这几个格局很开销非常的大,因为它会在各种子视图上起功用同时调用它们相应的
layoutSubviews 方法。注意:最棒不要在代码中手动调用 layoutSubviews
方法
。当 layoutSubviews 完成后,在 view 的持有者 view controller
上,会触发 viewDidLayoutSubviews 调用。因为 viewDidLayoutSubviews
view
布局更新后会被唯一可信调用的措施,所以你应有把全数依赖于布局依然大小的代码放在
viewDidLayoutSubviews 中,而不是放在 viewDidLoad 或者
viewDidAppear 中。

触发 layoutSubviews 的时机:

  • addSubview 方法会触发 layoutSubviews

  • viewFrame 产生变化也会接触layoutSubviews

  • 滚动三个 UIScrollView 会触发 layoutSubviews

  • 旋转荧屏会触发父 View 上的 layoutSubviews

  • 更改1个 View 大小的时候也会触发父 View 上的 layoutSubviews

  • setNeedsLayout触发 layoutSubviews
    调用的最省财富的方法就是在你的视图上调用 setNeedsLaylout
    方法,表示视图的布局必要再度计算。告知页面要求更新,但是不会马上伊始更新视图,视图会在下1个
    runloop 中更新,调用 setNeedsLaylout
    方法视图被重新绘制并布局里面会有一段任意时间的间隔。

  • layoutIfNeeded调用 layoutIfNeeded 会触发
    layoutSubviews,告知页面布局立时更新,所以一般都会和
    setNeedsLayout 一起行使。即使期望马上生成新的 frame
    要求调用此方法,利用那一点一般布局动画能够在创新布局后间接行使那一个艺术让动画片生效。

  • setNeedsUpdateConstraints告知供给立异约束,可是不会即时起先,在下贰回
    runloop 中更新约束,通过标记 update constraints 来触发
    updateConstraints

  • updateConstraintsIfNeeded告知立时更新约束,那几个格局与
    layoutIfNeeded 等价。它会检查 update constraints
    标记。借使以为这么些约束必要被更新,它会应声触发
    updateConstraints,而不会等到 run loop 的末尾。

  • updateConstraints系统更新约束,注意:无限不用在代码中手动调用
    updateConstraints 方法
    。通常在 updateConstraints
    方法中落到实处必须求更新的约束,在安装只怕解除约束、更改约束的优先级可能常量值,或许从视图层级中移除八个视图时都会安装贰个里面包车型客车标记
    update constarints,那一个标记会在下三个更新周期中触发调用
    updateConstrains

注意:layoutSubViews 在 drawRect 在此以前调用。

在运用 AutoLayout 的时候恐怕也会同时也会用到 frame,比如供给用到 layer
的时候,想让 layer
的尺码是由别的视图尺寸设定的,而以此视图又是由约束控制布局的,假诺将
layer 的早先化与 view 的开头化放在贰个方式中;比如:

layer.bounds = CGRectMake(0,0,view.bounds.size.widith * 0.5,50)

那么很恐怕拿到 layer 的幅度是0。

比如:

UIView *redView = [[UIView alloc] init];redView.backgroundColor = [UIColor redColor];[self.view addSubview:redView];self.redView = redView; // 设置约束[redView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); make.size.mas_equalTo(CGSizeMake;}]; NSLog(@"self.view 的尺寸%@,redView 的尺寸%@",self.view,redView);2017-06-08 15:32:51.815107+0800 MasonryDemo[42940:1076244] self.view 的尺寸<UIView: 0x7fd8cd408960; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x604000227200>>,redView 的尺寸<UIView: 0x7fd8cd407650; frame = ; layer = <CALayer: 0x6040002274a0>>

这一个时候,看到为何设置了束缚,而打字与印刷出来的 frame 是
,是因为约束被设置之后它并不会立即对 view 作出变动,而是要等到 layout
时,才会对视图的尺码进行修改,而 layout
平时是在视图已经加载到父视图上面时做出响应。

从而假如在 viewDidLoad 中装置了封锁,那么要等到 viewDidAppear 时 view
的尺寸才会真正改观。

消除办法:

- testLayout { UIView *redView = [[UIView alloc] init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; self.redView = redView; // 设置约束 [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); make.size.mas_equalTo(CGSizeMake; }];}- viewDidLayoutSubviews { [super viewDidLayoutSubviews]; NSLog(@"self.view 的尺寸%@,redView 的尺寸%@",self.view,self.redView);}2017-06-08 15:50:41.621147+0800 MasonryDemo[43363:1089098] self.view 的尺寸<UIView: 0x7fe412f0f780; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x604000238b00>>,redView 的尺寸<UIView: 0x7fe412e045b0; frame = (132 328; 150 80); layer = <CALayer: 0x60000003c460>>

一 、把拿到 frame 的设置写到 layoutSubviews 中或然写到
viewDidLayoutSubviews 中即可。因为 layout 约束生效时 view 的 center 或然bounds 就会被修改,当 center 或许 bounds 被改动时layoutSubview
就会被调用,随后 viewDidLayoutSubviews
就回被调用。那几个时候,设置约束的视图 frame 就不再是 了。

- testLayout { UIView *redView = [[UIView alloc] init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; self.redView = redView; // 设置约束 [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); make.size.mas_equalTo(CGSizeMake; }]; [redView setNeedsLayout]; [redView layoutIfNeeded]; NSLog(@"self.view 的尺寸%@,redView 的尺寸%@",self.view,redView);}2017-06-08 15:52:32.749105+0800 MasonryDemo[43419:1090641] self.view 的尺寸<UIView: 0x7fe36440b5f0; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x604000422100>>,redView 的尺寸<UIView: 0x7fe364405040; frame = (-75 -40; 150 80); layer = <CALayer: 0x6040004207a0>>

二 、假如将约束和 frame 写在同等方法中,写完约束就安装 frame,而不是想把
frame 的装置放到 layoutSubview
中,比如设置好约束后随即就想遵照约束的结果总结中度,那么必须在装置完约束之后手动调用setNeedsLayout
和 layoutIfNeeded 方法,让视图马上 layout,更新
frame,而是那个时候就能够得到实际的 size 并不能够获得实际的 center
,不提议这样使用

- testLayout { UIView *redView = [[UIView alloc] init]; redView.backgroundColor = [UIColor redColor]; [self.view addSubview:redView]; self.redView = redView; // 设置约束 [redView mas_makeConstraints:^(MASConstraintMaker *make) { make.centerX.equalTo(self.view.mas_centerX); make.centerY.equalTo(self.view.mas_centerY); make.size.mas_equalTo(CGSizeMake; }]; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ NSLog(@"self.view 的尺寸%@,redView 的尺寸%@",self.view,redView); });}2017-06-08 15:55:56.282546+0800 MasonryDemo[43500:1092911] self.view 的尺寸<UIView: 0x7fda85e0d540; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x600000233620>>,redView 的尺寸<UIView: 0x7fda85e0c770; frame = (132 328; 150 80); layer = <CALayer: 0x600000233540>>

3、在 dispatch_after 里面能够得到实际的 frame
,也许是因为安装约束和获取 frame 不在同一个 runloop 的因由呢。

相关文章