Upgrade to Pro — share decks privately, control downloads, hide ads and more …

iOSのレイアウトサイクルを知ろう

 iOSのレイアウトサイクルを知ろう

iOS(UIKit)のレイアウトサイクルについてのお話

Elvis Shi

May 24, 2018
Tweet

More Decks by Elvis Shi

Other Decks in Programming

Transcript

  1. var employedBy = "YUMEMI Inc." var job = "iOS Developer"

    var favoriteLanguage = "Swift" var twitter = "@lovee" var qiita = "lovee" var github = "el-hoshino" var additionalInfo = """ ࣗশ Auto Layout ઈରࡴ͢ϚϯͰ͢ """ class Me: Developable, Talkable { }
  2. UIView ͷੜ੒࣌ʹ௚઀ frame Λࢦఆ͠ɺ
 ϨΠΞ΢τͷมԽߟ͑ͳͯ͘΋Α͔ͬͨɻ ը໘ճస͕ແޮͳΒ let view = UIView(frame:

    CGRect(x: 0, ɹɹy: 0, ɹɹwidth: 320, ɹɹheight: 480)) Swiftɿ UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; Objective-Cɿ
  3. UIViewController UIView Needs layout? viewDidLayoutSubviews() layoutSubviews() updateViewConstraints() updateConstraints() yes no

    Needs update constraint? viewWillLayoutSubviews() yes sleep no Needs layout? no yes Disappear? viewDidDisappear() viewWillDisappear() layout runloop viewDidAppear() viewDidLayoutSubviews() layoutSubviews() viewWillLayoutSubviews() viewWillAppear() viewDidLoad() loadView()
  4. setNeedsLayout() Λݺͼग़ͨ͠ σόΠε͕ճసͨ͠ ࢠϏϡʔΛ௥Ճ΍࡟আΛͨ͠ ࣗ෼ͷϏϡʔ֊૚಺ͷ੍໿͕ߋ৽ͨ͠ ʢUIScrollView Ͱ͋ΔࢠϏϡʔʣ͕εΫϩʔϧͨ͠ ࣗ෼ͷࢠϏϡʔͷ frame ΍

    transform ͳͲ͕มߋ͞Εͨ ͳͲͳͲ… ͸Ͳ͏΍ͬͯ൑ఆ͍ͯ͠Δͷ͔ʁ Needs layout? ࣗ෼ͷ frame ΍ transform ͸
 ඞͣ਌ʹมߋͯ͠΋Β͓͏ʂ ࣗ෼ͷ frame ΍ transform Λมߋ͢Ε͹
 ਌ͷ layoutSubviews() ΋ݺ͹ΕΔʂ
  5. setNeedsLayout() Λݺͼग़ͨ͠ σόΠε͕ճసͨ͠ ࢠϏϡʔΛ௥Ճ΍࡟আΛͨ͠ ࣗ෼ͷϏϡʔ֊૚಺ͷ੍໿͕ߋ৽ͨ͠ ʢUIScrollView Ͱ͋ΔࢠϏϡʔʣ͕εΫϩʔϧͨ͠ ࣗ෼ͷࢠϏϡʔͷ frame ΍

    transform ͳͲ͕มߋ͞Εͨ ͳͲͳͲ… ͸Ͳ͏΍ͬͯ൑ఆ͍ͯ͠Δͷ͔ʁ Needs layout? ࠶ϨΠΞ΢τ͸ setNeedsLayout ͷ
 ௚ޙͰ͸ͳ͘ɺ࣍ͷϥϯϧʔϓ ϨΠΞ΢τ͸ίετ͕ߴ͍ ΋͘͠͸ layoutIfNeeded ݺͼग़࣌͠
  6. ίʔυʢ"VUP-BZPVUͳ͠ʣͰ૊Ή৔߹ class ViewController: UIViewController { lazy var myView = View(frame:

    UIScreen.main.bounds) override func loadView() { self.view = self.myView } override func viewDidLoad() { super.viewDidLoad() self.myView.button.addTarget(self, action: #selector(self.switchButtonSize), for: .touchUpInside) } @objc func switchButtonSize() { self.myView.showsLargeButton = !self.myView.showsLargeButton self.view.setNeedsLayout() } } class View: UIView { let button = UIButton() var showsLargeButton = false override func layoutSubviews() { if showsLargeButton { self.button.frame = self.bounds } else { self.button.frame.size = .init(width: 100, height: 100) self.button.frame.origin = .zero } } }
  7. ίʔυʢ"VUP-BZPVUͳ͠ʣͰ૊Ή৔߹ class ViewController: UIViewController { lazy var myView = View(frame:

    UIScreen.main.bounds) override func loadView() { self.view = self.myView } override func viewDidLoad() { super.viewDidLoad() self.myView.button.addTarget(self, action: #selector(self.switchButtonSize), for: .touchUpInside) } @objc func switchButtonSize() { self.myView.showsLargeButton = !self.myView.showsLargeButton self.view.setNeedsLayout() } } class View: UIView { let button = UIButton() var showsLargeButton = false override func layoutSubviews() { if showsLargeButton { self.button.frame = self.bounds } else { self.button.frame.size = .init(width: 100, height: 100) self.button.frame.origin = .zero } } }
  8. "VUP-BZPVUͰ૊Ή৔߹ class ViewController: UIViewController { lazy var button: UIButton =

    { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false button.addTarget(self, action: #selector(self.switchButtonSize), for: .touchUpInside) return button }() var showsLargeButton = false lazy var top = button.topAnchor.constraint(equalTo: view.topAnchor) lazy var left = button.leftAnchor.constraint(equalTo: view.leftAnchor) lazy var bottom = button.bottomAnchor.constraint(equalTo: view.bottomAnchor) lazy var right = button.rightAnchor.constraint(equalTo: view.rightAnchor) lazy var width = button.widthAnchor.constraint(equalToConstant: 100) lazy var height = button.heightAnchor.constraint(equalToConstant: 100) override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(button) self.view.setNeedsUpdateConstraints() } override func updateViewConstraints() { self.updateButtonConstraints() super.updateViewConstraints() } @objc func switchButtonSize() { self.showsLargeButton = !self.showsLargeButton self.updateButtonConstraints() } func updateButtonConstraints() { top.isActive = true left.isActive = true if showsLargeButton { bottom.isActive = true right.isActive = true width.isActive = false height.isActive = false } else { bottom.isActive = false right.isActive = false width.isActive = true height.isActive = true } } }
  9. "VUP-BZPVUͰ૊Ή৔߹ @objc func switchButtonSize() { self.showsLargeButton = !self.showsLargeButton self.updateButtonConstraints() }

    func updateButtonConstraints() { top.isActive = true left.isActive = true if showsLargeButton { bottom.isActive = true right.isActive = true width.isActive = false height.isActive = false } else { bottom.isActive = false right.isActive = false width.isActive = true height.isActive = true } }
  10. ίʔυʢ/PU"VUP-BZPVUʣͰ૊Ή৔߹ class ViewController: UIViewController { lazy var myView = View(frame:

    UIScreen.main.bounds) override func loadView() { self.view = self.myView } override func viewDidLoad() { super.viewDidLoad() self.myView.button.addTarget(self, action: #selector(self.switchButtonSize), for: .touchUpInside) } @objc func switchButtonSize() { self.myView.showsLargeButton = !self.myView.showsLargeButton self.view.setNeedsLayout() } } class View: UIView { let button = UIButton() var showsLargeButton = false override func layoutSubviews() { if showsLargeButton { self.nal.layout(button, by: { $0.stickOnParent() }) } else { self.nal.layout(button, by: { $0 .setTopLeft(by: { $0.topLeft }) .setSize(to: .init(width: 100, height: 100)) }) } } }