希望搞一次开放性的讨论,先描述问题:
在没有 autolayout 之前,我们在频繁变更 view 大小或者位置时,可以直接通过设置 view.frame,如:
view.frame = CGRectMake(x, y, width, height);
这是 view 的位置和大小都将按照最新的 frame 来展示。
但是,自从使用 autolayout 的最大困惑就是,autolayout 同一优先级的 constraint 不允许冲突,否则将会报错。所以如果一个 view 要频繁变更样式,不得不频繁的 addConstraint 和 removeConstraint,并且为了能够准确 removeConstraint,我们不得不在 addConstraint 时,保存 NSAutolayoutConstraint 的对象。
例如有这样的需求:
当键盘弹起时,我需要 view 的高度减小到 100.0;当键盘消失时,view 的高度变成 300.0。而现在的做法是,将高度 300 的 constraint 的优先级设定为 250 —— LOW,当键盘弹起时,我再给他 addConstraint,变成 300.0,优先级为 1000,同时缓存此 Constraint,并用一个 Dictionary 保存此 Constraint,记为 consHeight300,目的是为了在键盘消失时方便取出该对象,然后
[view removeConstraint:consHeight300];
这种频繁的新增到 Dictionary,然后 removeConstraint,而且你可能还要频繁的管理该 Dictionary 的值,我觉得其实非常麻烦,真心不如 frame 的方式。大家有什么好的办法么?是不是我们的做法有问题?
constraint 有一个唯一可以修改的属性 constant,我承认它的名字确实很具有迷惑性。。。
以题主提到的高度问题为例,可以保存这个高度 constraint 的引用,在键盘出现和收起时
objc
- (void)keyboardDidShowNotification { self.viewHeightConstraint.constant = 100.f; [self.myView layoutIfNeed]; } - (void)keyboardDidHideNotification { self.viewHeightConstraint.constant = 300.f; [self.myView layoutIfNeed]; }
如果是很复杂的 UI,constant 的修改不足以满足需求,那么频繁添加和移除 constraints 是不可避免的。但不得不说,这时候先要就 UI 设计小小做一下重新思考:)
补充:autolayout 同一优先级的 constraint 似乎并不是不允许冲突,而是 required 的 constraint 不允许冲突,因为它们必须全部满足。autolayout 底层的casowarry 算法我还没看懂(数学退化太严重了=。=),但稍微看了一下算法原作者的论文,优先级较低的约束是可以不全部满足的。
这是一个casowarry 的 Python 实现,题主可以参考下。
一句话: 题主不知道Constraint有constant属性。
1. 关于楼主所举例的键盘弹出弹入的问题
@NSFish 已经说的很详细了, 直接在监听函数中修改constant的值既能解决问题
2. 关于autolayout和frame
autolayout是一个远远超越frame的工具。我们以autolayout思维来解构frame的实现基础, view距父节点上边距为定值、距父节点左边距为定值、高度为定值、宽度为定值, 我们通过autolayout就能轻松构建这种约束条件
json
Constraint: leading space to superview, Constraint: top space to superview, Constraint: width, Constraint: height
对view添加上面这4个constraint后我们就能像使用frame一样来使用autolayout。所以autolayout是frame的超集,如果autolayout搞不定的UI, frame也绝无可能可以搞定。
就我个人使用autolayout来看, view就应该只有一套固定的Constraint, 初始化完成后就不应该再有addConstraint 和 removeConstraint之类的操作, 一个view有多套Constraint逻辑反而维护和修改都是非常麻烦的事情, 如果必须有这样的操作就应该重新设计你的Constraint条件。