これまで何時代の人だよという感じでframeで座標合わせしてましたが、最近ようやくAutoLayoutを触り出しました
でもStoryboardは使わず基本ソースコード上で扱い、残念(?)ながらNSLayoutConstraintはあんまり理解しないままTinyConstraintsというオープンソース触ってます
SnapKitなどがメジャーらしいですが、触った感じTinyConstraintsに落ち着きました
ここではその基本的な使い方を載せます
基本はREADMEやこちらに書いてる通りですけど詳細に書いたつもりです
環境
名前 | バージョン |
---|---|
TinyConstraints | 3.1.0 |
iOS | 10以上 |
Swift | 4.0 |
Simulator | iPhone SE, iPhone X |
大きさに関する制約
指定したviewと同じサイズ
let subView = UIView()
self.view.addSubview(subView)
//エッジを指定したビューに合わせる(今回は親ビュー)
subView.edges(to: self.view)
subView.backgroundColor = .red
上の場合のように親ビューと同じサイズにしたい場合は専用のメソッドがあります
//エッジを親ビューに合わせる
subView.edgesToSuperview()
余白をつける
//親ビューを緑にする
self.view..backgroundColor = .green
let subView = UIView()
self.view.addSubview(subView)
//エッジを親ビューに合わせる
subView.edgesToSuperview(insets: TinyEdgeInsets(top: 20, left: 20, bottom: 20, right: -20))
subView.backgroundColor = .red
TinyEdgeInsets
というのが出てきましたがただのUIEdgeInsets
のtypealias
です
SafeAreaに入らない大きさにする
ぶっちゃけこのためにTinyConstraintsを触ろうと思ったやつです
usingSafeAreaをtrueにしたらSafeAreaを考慮してレイアウトしてくれます
subView.edgesToSuperview(usingSafeArea: true)
大きさを比率で指定
//サイズを指定したビューの0.5倍にする
subView.size(to: self.view, multiplier: 0.5)
//centerを親ビューに合わせる
subView.centerInSuperview()
width
とheight
を別々に指定することもできます
subView.width(to: self.view, multiplier: 0.5)
subView.height(to: self.view, multiplier: 0.5)
subView.centerInSuperview()
親ビューに対する比率なので端末ごとに赤色のサイズは変わります
幅と高さを固定値で指定
固定の数値を入れるだけです
subView.width(100)
subView.height(200)
subView.centerInSuperview()
高さを指定したviewの横幅にする
自身の横幅に合わせると正方形になります
//幅と高さを親ビューの幅にする
subView.widthToSuperview()
subView.height(to: subView, subView.widthAnchor)
subView.centerInSuperview()
同様に指定したビューの高さの制約に合わせたいなら subView.heightAnchor
を指定すればいいです
位置に関する制約
指定したビューのセンターに合わせる
let subView = UIView()
self.view.addSubview(subView)
subView.width(100)
subView.height(to: subView, subView.widthAnchor)
//センターを指定したビューのセンターに合わせる
subView.center(in: view)
subView.backgroundColor = .red
上のように親ビューのセンターに合わせるならこう書けます
subView.centerInSuperview()
X座標とY座標を個別に親ビューのセンターに合わせるならこう書けます
subView.centerXToSuperview()
subView.centerYToSuperview()
上下左右の合わせ方
書くのが面倒になってきたので一気に6つ載せます
override func viewDidLoad() {
super.viewDidLoad()
self.setup()
}
func createSubView(superView:UIView, color:UIColor = .red)->UIView{
let subView = UIView()
superView.addSubview(subView)
subView.width(100)
subView.height(to: subView, subView.widthAnchor)
subView.backgroundColor = color
return subView
}
func setup(){
self.view.backgroundColor = .green
//左上
do{
let subView = createSubView(superView: self.view)
subView.leftToSuperview()
subView.topToSuperview()
}
//左真ん中
do{
let subView = createSubView(superView: self.view)
subView.leftToSuperview()
subView.centerYToSuperview()
}
//左下
do{
let subView = createSubView(superView: self.view)
subView.leftToSuperview()
subView.bottomToSuperview()
}
//真ん中上
do{
let subView = createSubView(superView: self.view)
subView.topToSuperview()
subView.centerXToSuperview()
}
//真ん中
do{
let subView = createSubView(superView: self.view)
subView.centerInSuperview()
}
//真ん中下
do{
let subView = createSubView(superView: self.view)
subView.bottomToSuperview()
subView.centerXToSuperview()
}
//右上
do{
let subView = createSubView(superView: self.view)
subView.topToSuperview()
subView.rightToSuperview()
}
//右真ん中
do{
let subView = createSubView(superView: self.view)
subView.centerYToSuperview()
subView.rightToSuperview()
}
//右下
do{
let subView = createSubView(superView: self.view)
subView.bottomToSuperview()
subView.rightToSuperview()
}
}
safeAreaに入らない位置に配置する
例によってこれが便利だと思ってます
上の例でsafeAreaに入らないようにします
//左上
do{
let subView = createSubView(superView: self.view)//自作メソッド
subView.leftToSuperview(usingSafeArea:true)
subView.topToSuperview(usingSafeArea:true)
}
//以下同様にusingSafeArea:trueを指定するだけ
オフセットを入れる
//自身のサイズの高さと幅の半分ずつずらす
let subView = createSubView(superView: self.view)//自作メソッド
subView.leftToSuperview(offset: subView.constraints.first!.constant/2)
subView.topToSuperview(offset: subView.constraints.first!.constant/2, usingSafeArea:true)
しれっと書きましたがsubView.constraints.first!.constant
で制約につけた数値を取得できます
周りのviewにくっつける
//真ん中
let centerView = createSubView(superView: self.view)
centerView.centerInSuperview()
//真ん中のviewの右側にくっつける
let rightView = createSubView(superView: self.view, color: .blue)
rightView.leftToRight(of: centerView)
rightView.centerY(to: centerView)
//真ん中のviewの下側にくっつける
let bottomView = createSubView(superView: self.view, color: .blue)
bottomView.topToBottom(of: centerView)
bottomView.centerX(to: centerView)
応用
これまでの制約の付け方を応用して以下のようなレイアウトを作ります
口でいうと
・真ん中に画面の横幅の半分の正方形ブロックを3つ並べる
・左側の余白に3つ目のブロックの上辺までの高さのバーを置く
・右側の余白に3つ目のブロックの底辺までの高さのバーを二つ置き、ひとつは幅が余白の0.3倍
・下側の余白にブロックを置く
self.view.backgroundColor = .green
let baseView = UIView()
self.view.addSubview(baseView)
baseView.edgesToSuperview()
baseView.backgroundColor = .white
let block1 = UIView()
baseView.addSubview(block1)
block1.width(UIScreen.main.bounds.width/2)
block1.height(to: block1, block1.widthAnchor)
block1.centerXToSuperview()
block1.topToSuperview()
block1.backgroundColor = .red
let block2 = UIView()
baseView.addSubview(block2)
block2.size(to: block1)
block2.centerX(to: block1)
block2.topToBottom(of: block1)
block2.backgroundColor = .blue
let block3 = UIView()
baseView.addSubview(block3)
block3.size(to: block1)
block3.centerX(to: block1)
block3.topToBottom(of: block2)
block3.backgroundColor = .black
let leftView = UIView()
baseView.addSubview(leftView)
leftView.leftToSuperview()
leftView.rightToLeft(of: block1)
leftView.topToSuperview()
leftView.bottom(to: block2)
leftView.backgroundColor = .gray
let rightBaseView = UIView()
baseView.addSubview(rightBaseView)
rightBaseView.leftToRight(of: block1)
rightBaseView.rightToSuperview()
rightBaseView.topToSuperview()
rightBaseView.bottom(to: block3)
let rightView1 = UIView()
rightBaseView.addSubview(rightView1)
rightView1.widthToSuperview(multiplier:0.3)
rightView1.heightToSuperview()
rightView1.leftToSuperview()
rightView1.topToSuperview()
rightView1.backgroundColor = .gray
let rightView2 = UIView()
rightBaseView.addSubview(rightView2)
rightView2.heightToSuperview()
rightView2.leftToRight(of: rightView1)
rightView2.rightToSuperview()
rightView2.topToSuperview()
rightView2.backgroundColor = .blue
let bottomView = UIView()
baseView.addSubview(bottomView)
bottomView.leftToSuperview()
bottomView.rightToSuperview()
bottomView.topToBottom(of: block3)
bottomView.bottomToSuperview()
bottomView.backgroundColor = .brown
safeAreaを考慮するとこんな感じです
コード的には最初のbaseView
のフラグをtrueにするだけ
//これまでは同じ
baseView.edgesToSuperview(usingSafeArea: true)
//あとも同じ
終わり
本当はアニメーションとかUIScrollViewとかUICollectionViewの制約とか実用的なとこまで書きたかったけど力尽きました
いつまで経ってもAutoLayoutの苦手意識が消えない自分がようやくTinyConstraintsのおかげでで実務でも使えるようになったので同じような苦手意識の人の助けになればなと思いまとめました
自分のメモのためにそのうち2も書きます