這個問題糾結了我挺長時間的。一直以為把約束直接添加到動畫里面就可以了。但是並沒那么簡單。-.-其實還是挺簡
class ViewController: UIViewController { @IBOutlet weak var usernameOutlet: UITextField! @IBOutlet weak var animateBtn: UIButton! let boxView = UIView() var topConstraint: Constraint? = nil @IBAction func animateBtnClick(sender: UIButton) { UIView.animateWithDuration(5) { self.boxView.snp_updateConstraints(closure: { (make) -> Void in make.top.equalTo(self.view).offset(30) }) self.view.layoutIfNeeded() // self.view.setNeedsDisplay() // self.view.setNeedsLayout() // self.view.layoutSubviews() } } override func viewDidLoad() { super.viewDidLoad() let tapGesture = UITapGestureRecognizer(target: self, action: "tapBg:") view.addGestureRecognizer(tapGesture) boxView.backgroundColor = UIColor.purpleColor() self.view.addSubview(boxView) boxView.snp_makeConstraints { (make) -> Void in self.topConstraint = make.top.equalTo(self.view).offset(400).constraint make.left.equalTo(self.view).offset(50) make.size.equalTo(CGSize(width: 80, height: 80)) } } }
對於這個layoutIfNeeded, 還有一個地方我們經常會碰到,就是設置約束我們如何才能立馬得到frame的數值:
view.superview. layoutIfneed()
今天要談的重點來了, iOS layout 相關機制
- (CGSize)sizeThatFits:(CGSize)size - (void)sizeToFit - (void)layoutSubviews - (void)lauoutIfNeeded - (void)setNeedsLayout - (void)setNeedsDisplay - (void)drawRect
1. layoutSubviews:
- init 不會觸發
- addsubview 會觸發
- 設置view的frame(有變化的)
- 滾動一個UIScroollView會
- 旋轉Screen,觸發父UIView上的layoutSubViews事件
- 直接調用setLayoutSubviews
- 直接調用setNeedsLayout
You should override this method only if the autoresizing behaviors of the subviews do not offer the behavior you want. // layoutSubviews, 當我們在某個類的內部調整子視圖位置時,需要調用。
刷新子對象布局:
- layoutSubviews: 不做任何事情,需要重寫
- setNeedsLayout: 標記為需要重新布局,異步調用layoutIfNeeded刷新布局,不立即刷新,但是layoutSubviews一定會被調用
- layoutIfNeeded: 如果有需要刷新新的標記,立即調用layoutSubviews進行布局
如果需要立即刷新,需要先view.setNeedsLayout()(設置標記),然后調用view.layoutIfneeded()立即刷新