iPadとPlaygroundsで学ぶ:「Auto Layout」と「制約」でビューをレイアウトする

今回はAuto Layoutの機能を使ってビューのレイアウトを行います。

Auto Layout

UIKitにはAuto Layoutという機能があり、制約(constraint)を指定することでメインビューやサブビュー同士の相対位置を指定することができます。

相対位置を指定できて何が良いかというと、メインビューのサイズが変わった場合にもうまく伸び縮みしてくれるということでしょうか。

前回のコードを変更して制約を試してみます。

仕様

  • メインビューの全体にマップビューを表示する(ただし上下左右10ptだけ隙間を開ける)
  • メインビューの右下に50pt x 50ptで赤色のボタンを表示する
  • ボタンの右下は右端から100pt、下端から100ptとする

コード

import UIKit
import MapKit

class ViewController : UIViewController {
    lazy var map = MKMapView()
    lazy var button = UIButton()
    
    override func loadView() {
        super.loadView()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.button.backgroundColor = UIColor.red
        self.button.addTarget(self, action:#selector(buttonEvent(_:)), for: UIButton.Event.touchUpInside)
        self.view.addSubview(self.map)
        self.view.addSubview(self.button)
        
        self.map.translatesAutoresizingMaskIntoConstraints = false
        self.map.leadingAnchor.constraint(equalTo:self.view.leadingAnchor, constant:10.0).isActive = true
        self.map.trailingAnchor.constraint(equalTo:self.view.trailingAnchor, constant:-10.0).isActive = true
        self.map.topAnchor.constraint(equalTo:self.view.topAnchor, constant:10.0).isActive = true
        self.map.bottomAnchor.constraint(equalTo:self.view.bottomAnchor, constant:-10.0).isActive = true
        
        self.button.translatesAutoresizingMaskIntoConstraints = false
        self.button.widthAnchor.constraint(equalToConstant: 50.0).isActive = true
        self.button.trailingAnchor.constraint(equalTo:self.view.trailingAnchor, constant:-100.0).isActive = true
        self.button.heightAnchor.constraint(equalToConstant: 50.0).isActive = true
        self.button.bottomAnchor.constraint(equalTo:self.view.bottomAnchor, constant:-100.0).isActive = true
    }
 
    @objc func buttonEvent(_ sender: UIButton) {
        self.map.centerCoordinate = CLLocationCoordinate2D(latitude: 35.0, longitude:135.0)
    }
}

import PlaygroundSupport
PlaygroundPage.current.liveView = ViewController()

viewDidLoadself.view.addSubviewより後に記述しているのが制約です。

(始めはaddSubviewより前に制約を書いていたためか実行時に途中で止まってしまい、しばらくハマりました)

また、viewDidLayoutSubviewsの記述がなくなっています。これは制約によりAuto Layoutが制約によりうまく配置といリサイズをしてくれるためです。

以下説明です。

Auto Layoutに位置とサイズを変更させる

ビューのtranslatesAutoresizingMaskIntoConstraintsfalseの場合は、Auto Layoutがビューのサイズと位置を変更するようになります。falseにしましょう。

制約

下記が制約とその制約を有効化する部分です。

self.map.leadingAnchor.constraint(equalTo:self.view.leadingAnchor, constant:10.0).isActive = true 

leadingAnchorは水平方向左側のアンカーで、constraintをコールしてself.viewの左側(leadingAnchor)から10.0ptの位置を指定しています。

さらに上記指定した後にisActive = trueで制約を有効にしています。