里头有多少个大旨的布局方法需求知道,常常不知道该怎么办而扬弃了动用 Autolayout

其中有几个基本的布局方法需要清楚,再次调试的时候就可以通过 lldb 来调试了

UIView是大家平日接收的叁在那之中央控件,此中有多少个着力的布局方法须求通晓。

刚初叶利用 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 的话。

进而交给你一个小手艺,增加

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 是大家常常利用的壹当中坚控件,当中有多少个为主的布局方法供给领悟。

  • 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

  • 改动加多个 View 大小的时候也会触发父 View 上的 layoutSubviews

  • setNeedsLayout触发 layoutSubviews
    调用的最省能源的点子正是在您的视图上调用 setNeedsLaylout
    方法,表示视图的布局需求再次总计。告知页面必要更新,可是不会应声早先更新视图,视图会在下一个
    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>>

1、把收获 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>>

2、如果将节制和 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 的原故吗。