【Swift UIKit】AutoLayoutとは?NSLayoutConstraint/NSLayoutAnchorの使い方

この記事からわかること

  • SwiftUIKitビュー真ん中配置する方法
  • AutoLayout使用して相対的位置指定する方法
  • AutoLayoutをStoryboard(Interface Builder)中心に配置する方法
  • エラーUnable to activate constraint with anchorsの原因
  • NSLayoutConstraint/NSLayoutAnchor/Visual Format Languageの使用方法

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

参考文献:Programmatically Creating Constraints

AutoLayoutとは?

AutoLayout」とはiOSアプリにおいてビューのサイズや位置を動的に計算して表示させるための機能のことです。

【Swift UIKit】ビューを画面の真ん中に配置する方法!AutoLayout

iOSのデバイスは機種によって画面のサイズが異なるので絶対的な数値を使ってサイズや位置を指定してしまうと想定していないデバイスで使用された際画面の向きを変更した際にレイアウトが崩れたり見た目が悪くなってしまいます。

制約:Constraint

これを解決できるのがAutoLayoutです。AutoLayoutではビューのサイズや位置を「制約(Constraint)」を用いて指定します。ここでいう制約とは「ビューの両端から画面まで距離は常に0pixel」や「X軸方向の中心にビューを固定する」と言ったルールを定義する感じです。

AutoLayoutはStoryboard(Interface Builder)からでもコードからでも指定することができますが、Apple公式からはInterface Builderでの設定が推奨されています。また複雑すぎる制約をかけてしまうと汎用性がなくなり、修正が困難になるので制約はできるだけ少なくすることがおすすめされています。

AutoLayoutはUIKitフレームワークを使用している場合に使用します。Swift UIの場合のレイアウト方法は異なります。

Storyboardから使用する

StoryboardからAutoLayoutを使用するにはInterface Builderの右下にある以下のアイコン部分から指定します。

【Swift UIKit】AutoLayoutとは?NSLayoutConstraint/NSLayoutAnchorの使い方

一番左のアイコンはAutoLayoutで指定された位置にビューも戻すボタンです。AutoLayoutで制約をかけた後にマウスなどで動かしてしまうと実際の表示(制約がかかった状態)と齟齬が生まれるのでこのボタンでリセットすることができます。

ビューを揃える

この5つ並んだアイコンのうち2つ目と3つ目を主に操作しながらAutoLayoutを使用していきます。例として画面にラベルビューを追加して制約を設けてみます。2つ目のアイコンをクリックすると以下のようなポップアップが表示されます。

【Swift UIKit】AutoLayoutとは?NSLayoutConstraint/NSLayoutAnchorの使い方

この状態で指定できるのは「Horizontal Center in Container」と「Vertical Center in Container」のみです。これは画面の中にビューが1つしか存在しないためです。2つ目のアイコンは複数のビューの間で制約をつけるので1つの場合はつけれる制約に限りがあります。指定できる項目は以下の通りです。

Horizontal Center in Container」と「Vertical Center in Container」にチェックを入れて「Add Constraint」をクリックすると制約が適応されます。この場合は親ビューに対して中心位置にビューを配置します。

複数のビューがある場合

ラベルビューをもう1つ配置して、2つを選択した状態で2つ目のアイコンをクリックすると以下のように全ての項目が選択可能になっています。例えば「Leading Edges(左端揃え)」を指定すると以下のように左端にラインが表示されビューが揃った配置になります。

【Swift UIKit】AutoLayoutとは?NSLayoutConstraint/NSLayoutAnchorの使い方

ビュー間の距離やサイズを定義する

3つ目のアイコンではビュー間の距離やビュー自体のサイズを定義することができます。

【Swift UIKit】AutoLayoutとは?NSLayoutConstraint/NSLayoutAnchorの使い方

追加した制約を確認/削除する

追加した制約はView Controller Sceneの中のConstraintsから確認することができます。選択して「backspace」キーを押すと削除することができます。

【Swift UIKit】AutoLayoutとは?NSLayoutConstraint/NSLayoutAnchorの使い方

また制約を選択すると画面上に対象の制約が表示されそこをダブルクリックすると編集することも可能です。

コードから使用する

コードからAutoLayoutを行うためには対象のビューに対して行わなければいけないことがあります。

この2つをやっておかないとAutoLayoutが効かなかったりエラーを引き起こす原因になるので注意してください。

translatesAutoresizingMaskIntoConstraintsプロパティ

translatesAutoresizingMaskIntoConstraintsはビューの配置に対してAutoresizingMaskかAutoLayoutのどちらを使用するか指定するプロパティです。falseを指定すると場合は、AutoLayoutになります。

具体的にはビューのframe(x, y, width, height)をframeやbounds、centerプロパティから直接操作することが可能かどうかを指定しています。trueにすると直接操作でき、falseにするとAutoLayoutの管理下になります。コードからビューを追加すると自動的にtrueにInterface Builderから追加すると自動的にfalseに設定されます。

Unable to activate constraint with anchors

AutoLayoutを使用したい場合はそのビューが既にビュー階層に追加されている必要があります。その前に制約を適応させようとすると以下のようなエラーを吐いてしまうので先にaddSubviewメソッドを使用してビューに追加しておきます。

"Unable to activate constraint with anchors <NSLayoutYAxisAnchor:0x6000010b1b40 \"UILabel:0x15fd09970.centerY\"> and <NSLayoutYAxisAnchor:0x6000010b3300 \"UIView:0x15fe07f50.centerY\"> because they have no common ancestor.  Does the constraint or its anchors reference items in different view hierarchies?  That's illegal."

制約(Constraint)の定義方法

SwiftではコードでAutoLayoutを適応させるための制約を定義する方法が3つ用意されています。

コードで制約を定義したらコード内からその制約を有効(active)にする必要がありやす。activeになっていない制約は適応されないので注意してください。

NSLayoutConstraintクラス

NSLayoutConstraintクラスは2つのビューに対して制約を定義するクラスです。制約はイニシャライザを使用して定義します。しかしこのクラスでの定義は可読性が低く、全てパラメーターに値を設定する必要があるため実用的ではありません。Apple公式からは次に紹介するNSLayoutAnchorクラスの使用が推奨されています。

convenience init(
    item view1: Any, // 制約の左側のビュー
    attribute attr1: NSLayoutConstraint.Attribute, // 制約の左側の属性
    relatedBy relation: NSLayoutConstraint.Relation, // 制約の左側と制約の右側の関係
    toItem view2: Any?, // // 制約の右側の属性
    attribute attr2: NSLayoutConstraint.Attribute, // // 制約の右側の属性
    multiplier: CGFloat, // 変更された属性を取得することの一部として、制約の右側にある属性を乗じた定数。
    constant c: CGFloat // 制約の右側にある乗算された属性値に追加された定数は、最終的に変更された属性を生成します。
)

親ビューの中心にビューを配置する制約

NSLayoutConstraint(item: label, attribute: .centerX, relatedBy: .equal, toItem: view, attribute: .centerX, multiplier: 1, constant: 0).isActive = true
NSLayoutConstraint(item: label, attribute: .centerY, relatedBy: .equal, toItem: view, attribute: .centerY, multiplier: 1, constant: 0).isActive = true

イニシャライザを使用し定義したら最後にisActiveプロパティにtrue渡すことで有効にします。

NSLayoutAnchorクラス

公式リファレンス:NSLayoutAnchor

NSLayoutAnchorクラスはコード量を抑えつつ、簡単に制約を定義することができます。ビューに元々定義されているアンカープロパティに値を設定することでビューに制約を設定します。制約はアンカープロパティからconstraintメソッドを呼び出して定義します。

親ビューの中心にビューを配置する制約

label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

同じ制約を定義してもコード量が抑えることができるのでコードで指定する場合はこのクラスを使用するのがおすすmです。

Visual Format Language

Visual Format LanguageASCIIアートのような文字列を使用して制約を定義する方法です。この方法はさらにコード量を抑えることができますが使用できる制約に制限があったり、実行するまでエラーか識別できなかったりなどデメリットも多いです。

let views = ["myView" : myView]
let formatString = "|-[myView]-|"
let constraints = NSLayoutConstraint.constraints(withVisualFormat: formatString, options: .alignAllTop, metrics: nil, views: views)
NSLayoutConstraint.activate(constraints)

使用例

コードからAutoLayoutの使用すること自体が公式よりあまり推奨されていませんが、使用する場合はNSLayoutAnchorクラスを使用するようにします。

以下は実際に対象ビューを親ビューの中心に配置する制約を定義した例です。

let label = UILabel()
label.text = "Test"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
label.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
label.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

またNSLayoutConstraintクラスのactivateメソッドを使用すればNSLayoutAnchorで定義した制約をまとめてアクティブにすることも可能です。

NSLayoutConstraint.activate([
    label.centerYAnchor.constraint(equalTo: view.centerYAnchor),
    label.centerXAnchor.constraint(equalTo: view.centerXAnchor)
])

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index