カテゴリー: iOS

[Swift3] コードで動的にオートレイアウトを変更する

はじめに

どうも、はじめです。

今回はコードでoutlayoutを変更する方法を覚えたので
記事にしてみようと思います。

今回紹介する方法は以下の3つです。
1.NSLayoutConstraintのActiveを切り替える
2.NSLayoutConstraintのActiveを切り替える(複数同時)
3.NSLayoutConstraintの値を変更する

今回は例として
ボタンを押すと画面中央に配置してあるViewのサイズが変更するものを
作ってみようと思います。

ではさっそくー

前提条件

Xcode 8.3.3
Swift 3.1

 

事前準備

まずは画面中央に表示するViewを配置します。
(サイズが変わっていることが分かるように背景を変えています。)

追加したViewに対して以下の制約を追加します。
※Aspectは1:1に設定しておきます。

 

左側の余白を定めた制約をoutlet接続します。
(以後DefaultMarginと呼びます)

次にボタンを押された後に反映したい制約も追加し、
outlet接続します。
・LeftMargin = 10
・LeftMargin = 100

この時制約の重複が発生するためstoryboard上でうまく変わってくれません。
先ほど追加したDefaultMarginの制約を選択し、installendのチェックを外します。
これで制約のActiveをfalseにすることができます。

 

最後にボタンを配置し、actionメソッドを作成します。

事前準備は以上になります。

 

1.NSLayoutConstraintのActiveを切り替える

OutLet接続した制約に対し、
isActiveの値を変更することで有効無効を切り替えることができます。

制約の変更をアニメーションさせたい場合はanimateメソッドないで
self.view.layoutIfNeeded()
と記載すると変更した制約をアニメーションさせることができます。

上記の方法で50のボタンが押された時の処理を実装します。

@IBAction func enableDefaultMargin(_ sender: Any) {
    // それぞれの制約のisActiveの値を変更する
    shotMargin.isActive = false
    longMargin.isActive = false
    defaultMargin.isActive = true
    
    // 制約の変更をアニメーションさせる
    UIView.animate(withDuration: 0.5, animations: {
        self.view.layoutIfNeeded()
    })
}

 

2.NSLayoutConstraintのActiveを切り替える(複数同時)

方法としては1と同じですがこちらの方法は複数の制約を切り替えたい場合に
見やすくかけるようになると思います。

上記の方法で10のボタンが押された時の処理を実装します。

@IBAction func enableShotMargin(_ sender: Any) {
    // NSLayoutConstraint型の変数を配列で渡して、
    // 複数の制約のisActiveの値を変更する
    let deActiveConstraints: [NSLayoutConstraint] = [defaultMargin, longMargin]
    NSLayoutConstraint.deactivate(deActiveConstraints)
    NSLayoutConstraint.activate([shotMargin])

    UIView.animate(withDuration: 0.5, animations: {
        self.view.layoutIfNeeded()
    })
}

 

以上で今回の実装は終わりです。
最終的な全ソースを載せておきます。

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var defaultMargin: NSLayoutConstraint!
    @IBOutlet weak var shotMargin: NSLayoutConstraint!
    @IBOutlet weak var longMargin: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func enableDefaultMargin(_ sender: Any) {
        // それぞれの制約のisActiveの値を変更する
        shotMargin.isActive = false
        longMargin.isActive = false
        defaultMargin.isActive = true
        
        // 制約の変更をアニメーションさせる
        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        })
    }

    @IBAction func enableShotMargin(_ sender: Any) {
        // NSLayoutConstraint型の変数を配列で渡して、
        // 複数の制約のisActiveの値を変更する
        let deActiveConstraints: [NSLayoutConstraint] = [defaultMargin, longMargin]
        NSLayoutConstraint.deactivate(deActiveConstraints)
        NSLayoutConstraint.activate([shotMargin])

        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        })
    }

    @IBAction func enableLongMargin(_ sender: Any) {
        shotMargin.isActive = false
        defaultMargin.isActive = false
        longMargin.isActive = true
        longMargin.constant = 150

        UIView.animate(withDuration: 0.5, animations: {
            self.view.layoutIfNeeded()
        })
    }
}

 

3.NSLayoutConstraintの値を変更する

最後に今回の実装では使用していませんがoutlet接続した制約の値を変更する方法があります。

例としてボタンを押された時、100ある余白を150に変更する処理を書くと以下のようになります。

longMargin.constant = 150
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})

 

さいごに

最近スクロールビューを使用する機会があったのですが、
なんじゃこのオートレイアウトは。。。ってなりましたw
CollectionViewも先日初めて使いましたがまだまだ使い慣れないので、
早く使い慣れたいです。

今回も最後まで見ていただいてありがとうございました。

hajimenagasawa

シェア
執筆者:
hajimenagasawa
タグ: Swift

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前