Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
iOSのレイアウトサイクルを知ろう
Search
Elvis Shi
May 24, 2018
Programming
2k
3
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
iOSのレイアウトサイクルを知ろう
iOS(UIKit)のレイアウトサイクルについてのお話
Elvis Shi
May 24, 2018
More Decks by Elvis Shi
See All by Elvis Shi
為什麼你並不需要ViewModel / No, you don't need a ViewModel
lovee
1
580
@Environment(\.keyPath)那么好我不允许你们不知道! / atEnvironment keyPath is so good and you should know it!
lovee
0
580
ゼロから始めるPreferenceの実装 / Let's implement Preferences from scratch
lovee
0
160
Kotlin エンジニアへ送る:Swift 案件に参加させられる日に備えて~似てるけど色々違う Swift の仕様 / from Kotlin to Swift
lovee
1
410
個人アプリを2年ぶりにアプデしたから褒めて / I just updated my personal app, praise me!
lovee
0
800
How did I build an Open-Source SwiftUI Toast Library
lovee
1
190
SwiftUIで使いやすいToastの作り方 / How to build a Toast system which is easy to use in SwiftUI
lovee
3
1.3k
SwiftUIで二重スクロール作ってみた / When I tried to make a dual-scroll-ish view in SwiftUI
lovee
1
390
Observation のあれこれ / A brief introduction about Observation
lovee
3
460
Other Decks in Programming
See All in Programming
[Dev Group Paris Octobre 26] Agentforce, SIforce, Claudeforce, Slackbot… on s'y retrouve ?
nabondance
0
120
PumaからFalconに移行したRailsアプリケーションでの実践
falcon8823
0
310
baseline으로 마이그레이션, 리팩토링 안전하게 맡기기
fornewid
1
690
AIで開発が速くなった先で、開発チームは何を目指すか
shihochan
1
1.9k
Long Living Tokens, Die, Die, Die! (or: The One Ring is Banned in Modern)
sylph01
0
400
Apple Intelligenceとオンデバイス時代の到来
yahir0
0
180
クラウドエージェントは、 何がそんなに便利なのか / what makes cloud agents so useful
rkaga
3
640
AI時代のTerminal環境を UNIX哲学で設計・運用する
yasunori0418
1
320
Seven New Principles of Software Engineering
yegor256
0
400
선언형 햅틱 라이브러리 진동을 소개합니다
l2hyunwoo
1
180
Inertia Rails: The One-Person Framework with React & Friends
skryukov
0
200
AmebaブログはKMPから卒業します
kmars0605
0
310
Featured
See All Featured
Deep Space Network (abreviated)
tonyrice
0
400
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
33
5.5k
Speed Design
sergeychernyshev
33
2.2k
How to make the Groovebox
asonas
2
2.5k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
620
Code Reviewing Like a Champion
maltzj
529
40k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
Gemini Prompt Engineering: Practical Techniques for Tangible AI Outcomes
mfonobong
2
610
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8.4k
The World Runs on Bad Software
bkeepers
PRO
72
12k
SEOcharity - Dark patterns in SEO and UX: How to avoid them and build a more ethical web
sarafernandez
0
310
Introduction to Domain-Driven Design and Collaborative software design
baasie
1
1.1k
Transcript
ϨΠΞταΠΫϧΛ Ζ͏ forαϙʔλʔζ$P-BCษڧձ K15؊
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 { }
J04ʢ6*,JUʣͷϨΠΞταΠΫϧͲͷΑ͏ʹಈ͍ͯΔ͔ ͲͷλΠϛϯάͰϨΠΞτΛΈͳ͓͖͔͢ "VUP-BZPVUͰϨΠΞτΛΉ࣌ͱίʔυͰϨΠΞτ Ή࣌ʹͦΕͧΕԿΛؾΛ͚ͭΔ͖͔ /PU"VUP-BZPVUͷ͍ܰએʢΛ͍ͤͯͩ͘͞͞Xʣ ࠓ͢͜ͱ
͜ͷϨΠΞτ۩ମతʹͲͷΑ͏ʹΜͰ͍Δͷ͔ έʔεόΠέʔε͗͢ΔͷͰΧόʔ͢Δͷແཧ Ͱฉ͖͍ͨͷ͋Ε࣭ٙԠ࠙ձͷ࣌ʹରԠ͍ͨ͠ "VUP-BZPVUͷΈ ڵຯֶ͋ͬͯಘҙͳϑϨϯζੋඇҴݟ͞ΜͷൃදΛ IUUQTXXXZPVUVCFDPNXBUDI W5)0OTZ%,&:2UT ࠓ͞ͳ͍͜ͱ
ੲͷ iPhone ղ૾͕ 1 छྨ͔͠ͳ͘ɺ ը໘ϨΠΞτ͕ͱͯ؆୯ͩͬͨɻ
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ɿ
్த͔Βը໘छྨ͕૿͑ɺ ϨΠΞτ͕໘ʹͳΓ࢝Ίͨɻ
ࠓछྨ͕ଟ͗ͯ͢ɺ ԿΛͲ͏͢Ε͍͍͔… ?
ϨΠΞτ αΠΫϧ
ϨΠΞτίετ͕ߴ͍ʢॏ͍ʣ ͳΔ͘ϨΠΞτΛඞཁͳ࣌ʹඞཁ࠷ݶ͚ͩߦ͍͍ͨ ҙਤ͠ͳ͍ॴͰ࠶ϨΠΞτΛىͤͨ͘͜͞ͳ͍ ϨΠΞτΛࢥ͏Ͳ͓Γʹ࣮ݱ͢Δͷʹඞཁ ϨΠΞτઃఆͯ͠Δ͚ͲɺαΠΫϧ͕ճΒͳ͔͍ͬͨͤ Ͱݟ͕ͨఆͱҧ͏͜ͱΛ͍͗ͨ ͳͥϨΠΞταΠΫϧ͕ॏཁ͔
UIViewController UIView viewDidDisappear() viewWillDisappear() layout runloop viewDidAppear() viewDidLayoutSubviews() layoutSubviews() viewWillLayoutSubviews()
viewWillAppear() viewDidLoad() loadView()
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()
setNeedsLayout() Λݺͼग़ͨ͠ σόΠε͕ճసͨ͠ ࢠϏϡʔΛՃআΛͨ͠ ࣗͷϏϡʔ֊ͷ੍͕ߋ৽ͨ͠ ʢUIScrollView Ͱ͋ΔࢠϏϡʔʣ͕εΫϩʔϧͨ͠ ࣗͷࢠϏϡʔͷ frame
transform ͳͲ͕มߋ͞Εͨ ͳͲͳͲ… Ͳ͏ͬͯఆ͍ͯ͠Δͷ͔ʁ Needs layout?
setNeedsLayout() Λݺͼग़ͨ͠ σόΠε͕ճసͨ͠ ࢠϏϡʔΛՃআΛͨ͠ ࣗͷϏϡʔ֊ͷ੍͕ߋ৽ͨ͠ ʢUIScrollView Ͱ͋ΔࢠϏϡʔʣ͕εΫϩʔϧͨ͠ ࣗͷࢠϏϡʔͷ frame
transform ͳͲ͕มߋ͞Εͨ ͳͲͳͲ… Ͳ͏ͬͯఆ͍ͯ͠Δͷ͔ʁ Needs layout? ࣗͷ frame transform ඞͣʹมߋͯ͠Β͓͏ʂ ࣗͷ frame transform Λมߋ͢Ε ͷ layoutSubviews() ݺΕΔʂ
setNeedsLayout() Λݺͼग़ͨ͠ σόΠε͕ճసͨ͠ ࢠϏϡʔΛՃআΛͨ͠ ࣗͷϏϡʔ֊ͷ੍͕ߋ৽ͨ͠ ʢUIScrollView Ͱ͋ΔࢠϏϡʔʣ͕εΫϩʔϧͨ͠ ࣗͷࢠϏϡʔͷ frame
transform ͳͲ͕มߋ͞Εͨ ͳͲͳͲ… Ͳ͏ͬͯఆ͍ͯ͠Δͷ͔ʁ Needs layout? ࠶ϨΠΞτ setNeedsLayout ͷ ޙͰͳ͘ɺ࣍ͷϥϯϧʔϓ ϨΠΞτίετ͕ߴ͍ ͘͠ layoutIfNeeded ݺͼग़࣌͠
Ͳ͏ϨΠΞτ ͢Ε͍͍͔
جຊUIViewͷlayoutSubviewsΛΦʔόʔϥΠυ͠ɺͦ ͷதͰϨΠΞτ͢Ε͍͍ ϏϡʔͷframeϓϩύςΟʔɺ͕ཧ͖͢ ༰ʹԠͯ͡αΠζ͕มΘΔϏϡʔɺsizeThatFitsͰ ͳΜͱ͔ͳΔ label.frame.size = label.sizeThatFits(bounds.size) ඞཁʹԠͯ͡ΦʔόʔϥΠυՄ ࠶ϨΠΞτ͕ඞཁʹͳͬͨΒsetNeedsLayoutΛݺͿ
ϨΠΞτ͕ඞཁͱ͍͏ϑϥάཱ͕͚ͭͩͳͷͰɺҰͷ ॲཧʹෳճݺΜͰϨΠΞτޙͰҰճ͚ͩճΔ ίʔυʢ"VUP-BZPVUͳ͠ʣͰΉ߹
ίʔυʢ"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 } } }
ίʔυʢ"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 } } }
"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 } } }
"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 } }
ϨΠΞτʢʹݶΒͣ6*ܥશൠʣϝΠϯεϨουͰʂ ϨΠΞταΠΫϧͰϨΠΞτҾ͖ى͜͞ͳ͍ setNeedsLayoutsetNeedsUpdateConstraintsΛ ݺͳ͍ ϨΠΞταΠΫϧͷݺͼग़͠ΛͳΔ͘࠷খݶʹ ࢠϏϡʔͷՃͳΔ͘viewDidLoad͔ viewWillLayoutSubviewsʹ layoutIfNeededΛΉΈʹݺͳ͍ ຊʹඞཁͳ͚࣌ͩݺͿ ҙʢڞ௨ʣ
ΞχϝʔγϣϯϒϩοΫͱ͔
sizeThatFitsΛ͏·͘׆༻͠ɺϨΠΞτॲཧΛ࠷খݶʹ ͑Δ sizeThatFitsͷΦʔόʔϥΠυ͢Δ࣌ʹɺதͰͳΔ͘ ϨΠΞτॲཧͤ͞ͳ͍ ࣗࣗͰࣗࣗͷframeΛมߋ͠ͳ͍ʂ ҙʢίʔυʣ
ϏϡʔؔΛ͏·͘׆༻੍ͯ͠ΛΉ ؔੑΛਖ਼͘͠ઃఆͰ͖ͯΕsetNeedsLayout(); layoutIfNeeded()ͷίϯϘཁΒͳ͍ͣʂ ੍ͷߋ৽සΛͳΔ͘࠷খݶʹ ՄೳͳݶΓ੍Λੜʗআ͢ΔͷͰͳ͘ɺಉ੍͡ Λྲྀ༻͠constantsΛมߋ͢Δ͔ɺ੍ΛisActiveͰ Γସ͑Δ isActiveͰΓସ͑Δ߹੍ͷอ࣋ʹҙ ίϯςϯπʹԠͨ͡αΠζઃఆintrinsicContentSize ΛΦʔόʔϥΠυ
ҙʢ"VUP-BZPVUʣ
એ
/PU"VUP-BZPVUઈࢍެ։த IUUQTHJUIVCDPNFMIPTIJOP/PU"VUP-BZPVU
ίʔυʢ/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)) }) } } }
J04ΞϓϦઃܭύλʔϯೖࣥචܾఆ IUUQTQFBLTDDJ04@BSDIJUFDUVSF
גࣜձࣾΏΊΈɺΤϯδχΞืूத IUUQTXXXZVNFNJDPKQKBQBHFSFDSVJU