どうも、フリーランスのITエンジニア兼ブロガー兼投資家のKerubitoです。
AutoLayoutをコードで書きたい!
なんていうことがたまにあると思います。
直感的にはわかりづらいですが、動的な画面を作る際にはどうしてもStoryBoardでは難しいことがあります。
StoryBoardでもActiveかどうかで切り替えたりできますが、そうなると一気に可読性が悪くなるんですよね。
たまにStoryBoard上で匠の技レベルの制約を見かけますが、非常に見づらい。
それならコードで書いたほうがマシ。
しかし、コードで書くとはまるポイントがいくつかあります。
本記事では自分への備忘録も兼ねて、AutoLayoutをコードで書く際の注意点をまとめてみました。
環境は以下の通りです。
・Swiftバージョン:5
・Xcodeバージョン:11.6
・使用デバイス:iPhone8(14.2)
AutoLayoutをコードで書くときの参考になれば幸いです。
Does the constraint or its anchors reference items in different view hierarchies? That's illegal.
制約を入れて、ビルドも通って、いざ実行。
すると以下のようなエラーが出ます。
'Unable to activate constraint with anchors <NSLayoutXAxisAnchor:0x283011100 "***.centerX" (names: ***:0x10ca14980)> and <NSLayoutXAxisAnchor:0x283016a40 "***.CustomWindow:0x105f1a850.centerX"> because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.'
適当に訳すと「そんなオブジェクトはいないけど、なんか階層とか間違ってんじゃねえの?」ってなことを言っています。
そんなわけないだろうと思いますが、コードは以下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | let label = UILabel() label.backgroundColor = UIColor.black.withAlphaComponent(0.6) label.textColor = UIColor.white label.textAlignment = .center; label.font = UIFont(name: "Montserrat-Light", size: 12.0) label.text = "hogehoge" label.alpha = 1.0 label.numberOfLines = 0 label.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true label.centerYAnchor.constraint(equalTo: self.viewview.centerYAnchor).isActive = true label.widthAnchor.constraint(equalTo: self.viewview.widthAnchor, multiplier: 0.2).isActive = true label.heightAnchor.constraint(equalTo: self.viewview.heightAnchor, multiplier: 0.1).isActive = true view.addSubview(label) |
原因は制約を追加する前にaddSubviewしないと、オブジェクトがないって怒られるんですね。
制約を入れた部品が表示されない
上のソースのままだと、UILabelは表示されません。
label.frame = self.view.frame
といった感じで制約を入れる前に一度frameを設定しないといけないようです。
制約を入れた部品が正しく表示さえない
なぜかちゃんと指定しているはずの制約が正しく効かない。
ということがたまにあります。
原因の一つがtranslatesAutoresizingMaskIntoConstraintsというプロパティです。
translatesAutoresizingMaskIntoConstraintsはAuto Layout以前に使われていた、Autosizingという仕組みをAuto Layoutに変換するかどうかを設定するフラグです。
デフォルトはオンなのですが、このままだと制約が正しく効かない場合があります。
なので
label.translatesAutoresizingMaskIntoConstraints = false
といった感じでオフにしておきましょう。
AutoLayoutをコードで書くときの正しい例
最後に上のコードでいう正しい例を載せておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | let label = UILabel() label.frame = view.frame label.translatesAutoresizingMaskIntoConstraints = false label.backgroundColor = UIColor.black.withAlphaComponent(0.6) label.textColor = UIColor.white label.textAlignment = .center; label.font = UIFont(name: "Montserrat-Light", size: 12.0) label.text = "hogehoge" label.alpha = 1.0 label.numberOfLines = 0 view.addSubview(label) label.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true label.centerYAnchor.constraint(equalTo: self.viewview.centerYAnchor).isActive = true label.widthAnchor.constraint(equalTo: self.viewview.widthAnchor, multiplier: 0.2).isActive = true label.heightAnchor.constraint(equalTo: self.viewview.heightAnchor, multiplier: 0.1).isActive = true |
楽しい開発ライフを!