LoginSignup
17
20

More than 5 years have passed since last update.

コードでAutoLayout-入門

Last updated at Posted at 2018-03-04

これまで何時代の人だよという感じで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というのが出てきましたがただのUIEdgeInsetstypealiasです

SafeAreaに入らない大きさにする

ぶっちゃけこのためにTinyConstraintsを触ろうと思ったやつです
usingSafeAreaをtrueにしたらSafeAreaを考慮してレイアウトしてくれます

subView.edgesToSuperview(usingSafeArea: true)

大きさを比率で指定

//サイズを指定したビューの0.5倍にする
subView.size(to: self.view, multiplier: 0.5)
//centerを親ビューに合わせる
subView.centerInSuperview()

widthheightを別々に指定することもできます

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も書きます

17
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
20