SwiftでAuto Layoutを設定した場合、その直後ではframeやboundsプロパティから正しい座標が取得できません。
例えば、ViewControllerにこんな感じでUIViewを作ると、4辺が全て0のRectが返されます。
override func viewDidLoad() { super.viewDidLoad() let viewA = UIView() viewA.setTranslatesAutoresizingMaskIntoConstraints(false) self.view.addSubview(viewA) let constraints = [ NSLayoutConstraint(item: viewA, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 10), //x=10 NSLayoutConstraint(item: viewA, attribute: .Top, relatedBy: .Equal, toItem: self.view, attribute: .Top, multiplier: 1.0, constant: 10), //y=10 NSLayoutConstraint(item: viewA, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 100), //幅=10 NSLayoutConstraint(item: viewA, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1.0, constant: 50), //高さ=10 ] self.view.addConstraints(constraints) println(viewA.frame) <<(0.0,0.0,0.0,0.0) }
そんな時は、layoutIfNeeded()メソッドを呼ぶと正しい座標が呼ばれるようになります。
viewA.layoutIfNeeded() println(viewA.frame) <<(10.0,10.0,100.0,50.0)
ただ、UIViewに対して直接layoutIfNeeded()を呼ぶと、Viewが入れ子になっていた場合には直近のsuperviewからの座標しか再計算されません。
viewAのsubviewの画面上の座標を計算しようとしても正しく計算されません。
subView.layoutIfNeeded() let displayRect = subView.convertRect(subView.bounds, toView: self.view) //self.viewのselfはViewController println(displayRect) <<直接の親Viewからの相対位置が返される
これを解決するには、ViewControllerのviewプロパティのlayoutIfNeeded()メソッドを呼ぶことです。
self.view.layoutIfNeeded() let displayRect = subView.convertRect(subView.bounds, toView: self.view) //self.viewのselfはViewController println(displayRect) <<画面上の絶対座標が取れるようになる
swift-layout
ちなみに、先々週から作っているswift-layoutでは、displayRect()で画面上の絶対座標を取得できます。
let viewA = Layout.registUIView(superview: self.view) .left(10).fromSuperviewLeft() .top(10).fromSuperviewTop() .width(100) .height(50) .backgroundColor(UIColor.redColor()) let subView = Layout.registUIView(superview: viewA.target) .left(30).fromSuperviewLeft() .top(15).fromSuperviewTop() .width(20) .height(20) .backgroundColor(UIColor.blueColor()) println(subView.displayRect()) //(40.0,25.0,20.0,20.0)