Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AutoLayout以外の選択肢
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Muukii
March 28, 2018
Programming
5.4k
13
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
AutoLayout以外の選択肢
Muukii
March 28, 2018
More Decks by Muukii
See All by Muukii
Problem Solving from the Abstraction Layer
muukii0803
1
68
Pairs iOSとトレンドの技術
muukii0803
0
1k
Thoughts about build flow
muukii0803
2
360
スマホアプリ開発で大切なこと
muukii0803
3
190
エンジニアとして働くために
muukii0803
0
210
Q. Textureは部分的に導入できますか?
muukii0803
3
2.6k
安定したチャットを実現するための アプリとAPI設計
muukii0803
17
8.5k
快適なUIを持つアプリを作るために できること
muukii0803
12
2.8k
iOS エンジニアが考える Webアプリ開発
muukii0803
3
530
Other Decks in Programming
See All in Programming
その問い、本当に正しいですか?AI時代のエンジニアに必要な哲学と認知科学 / ai-philosophy-cognitive-science
minodriven
11
5.9k
Observability in Practice:Grafana 與 Edge Device SRE 的那些事
blueswen
0
170
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
710
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
14
5.6k
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
190
AIで効率化できた業務・日常
ochtum
0
140
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
350
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
370
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
210
Strategic Design in the Frontend: Moduliths & Micro Frontends @DDDEurope
manfredsteyer
PRO
0
110
Go1.27で導入されるジェネリクスメソッドでできること
mackee
0
140
依存関係から依存物へ―Dependencyという言葉の歴史をひも解く
j_lee
0
120
Featured
See All Featured
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Become a Pro
speakerdeck
PRO
31
6k
AI in Enterprises - Java and Open Source to the Rescue
ivargrimstad
0
1.3k
Learning to Love Humans: Emotional Interface Design
aarron
275
41k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
540
Exploring anti-patterns in Rails
aemeredith
3
410
Faster Mobile Websites
deanohume
310
31k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
32
3.5k
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
Transcript
AutoLayoutҎ֎ͷબࢶ @muukii Akiba.swift 2018.03.28
About Me ‣ muukii <Hiroshi Kimura> ‣ iOS Engineer at
eureka, Inc. ‣ Pairs Global Team ‣ GitHub : @muukii ‣ https://muukii.me ☕ ⌚
None
Agenda › AutoLayoutͷύϑΥʔϚϯεͱସҊ › ͲΜͳ࣌ʹAutoLayoutͷύϑΥʔϚϯε͕ʹͳΔͷ͔ › ผͷϨΠΞτΤϯδϯͷհ › TextureGroup/Texture (AsyncDisplayKitʣʹ͍ͭͯհ
› ͍ํͷงғؾ (࣌ؒ͋Ε) › AutoLayoutʹର͢Δײ
ίʔυͰAutoLayoutॻ͘ͳΒ › SnapKit/SnapKit › PureLayout/PureLayout › robb/Cartography <= Couples ͱ
Pairs ຊ൛Ͱ༻த › stevestreza/Relayout › freshOS/Stevia › roberthein/TinyConstraints › nakiostudio/EasyPeasy <= ࠓͷͱ͜Ζ͓ؾʹೖΓͰւ֎൛PairsͰར༻த › Raizlabs/Anchorage › and more
AutoLayoutͷύϑΥʔϚϯε
AutoLayout੍ͷ͕૿͑Δͱ͘ͳ͍ͬͯ͘ Ҿ༻ : https://github.com/layoutBox/FlexLayout#performance AutoLayout ManualLayout
AutoLayout͕͘ͳΔ࣌ › ੍ͷ͕ଟ͍࣌ (੍ಉ࢜ͷܨ͕Γ͕ଟ͍࣌) › ༰ʹԠͯ͡େ͖͕͞มԽ͢Δίϯϙʔωϯτ͕ଟؚ͘·ΕΔ࣌ › intrinsicContentSizeΛར༻ͨ͠ϨΠΞτ › UILabelͳͲͰwidth,
heightͷ੍Λ͚ͭͳ͍࣌
͜ΜͳϨΠΞτ
͍ͱԿ͕ى͖Δʁ › UIεϨου͕ϒϩοΫ͞ΕΔ͕࣌ؒ͘ͳ͍ͬͯ͘ › ಈ͖͕͘ͳΓɺΒ͔ʹΞϓϦ(UI)͕ૢ࡞Ͱ͖ͳ͘ͳΔ › UXͷԼʹͭͳ͕͍ͬͯ͘ › ετϨε͕ཷ·Δ? ›
͕ർΕΔ?
1. AutoLayout͕ϘτϧωοΫʹͳΔέʔε › εΫϩʔϧ͢ΔUI › ϦετܥͷUI (UICollectionView/UITableView)ͷCellͷϨΠΞτʹ༻͞ Ε͍ͯΔ࣌ › ྫ
: iOSͷ௨ηϯλʔ (࠷ۙͷσόΠεͩͱΘ͔ΓͮΒ͍͔) › εΫϩʔϧ࣌ʹCellͷதͷϨΠΞτ͕͍ͱද͕ࣔΕΔ › ϑϨʔϜ͕མͪΔ › δϟϯϓ͍ͯ͠ΔΑ͏ʹݟ͑Δ › Ͱ͏ͷ͕େม
2. AutoLayout͕ϘτϧωοΫʹͳΔέʔε › ը໘ભҠͷͱ͖ › ભҠઌͷViewControllerͷϨΠΞτ͕ෳࡶͩͱॳظදࣔͷϨΠΞ τʹ͕͔͔࣌ؒΔ › ભҠΛߦ͏ϘλϯΛλοϓ͔ͯ͠ΒҰॠݻ·ΓભҠ͕ߦΘΕΔ Α͏ͳݟͨʹͳΔ
› Ԡ͕͘ײ͡ΔͷͰɺͬ͞Γͨ͠ΞϓϦʹݟ͑Δ
Ͳͷ͙Β͍ʹͳΔͷ͔? › ϨΠΞτ͚ͩͰ͋ΕͦΜͳʹʹͳΒͳ͍ › ͔͠͠ɺͦͷ΄͔ͷϩδοΫ͕ೖΔ͜ͱʹΑΓϨΠΞτͷॲཧ ͕࣌ؒϘτϧωοΫͱͳΔ
UI͕ߴʹಈ࡞͢ΔͨΊʹʁ › ը໘ͷϦϑϨογϡϨʔτ60Hz => ΠϕϯτϧʔϓͰϒϩοΫͯ͠ྑ͍࣌ؒ 16ms (1000ms / 60) ›
16msΛ͍͑ͯ͘ͱϑϨʔϜ͕ͲΜͲΜམ͍ͪͯ͘(υϩοϓϑϨʔϜ) › ͜ͷؒʹUIKitࣗମͷॲཧೖΔͷͰࢲ͕ͨͪॻ͘ίʔυ10ms͙Β͍ʹ͍ͨ͠ ͷ › ࠷ۙͷiPad Pro120HzʹͳͬͯΔͷͰɺͬͱ͘͠ͳ͍ͱσΟεϓϨΠͷՁ ൃش͞Εͳ͍ɻૢ࡞ʹΑΔεΫϩʔϧͷ͞ʹCellͷද͕͍͔ࣔͭͳ͚Εͳ Βͳ͍ɻ ͦͦ
UI͕ߴʹಈ࡞͢ΔͨΊʹʁ › ͔͠͠ɺͲΜͳʹࣗͨͪͷίʔυΛ࠷దԽͯͦ͠ͷݶք͋Δ › AutoLayoutͷίετΛݮΒ͢ͷ͍͠ ϨΠΞτॲཧ ϨΠΞτॲཧ ͦͷଞϩδοΫ ͦͷଞϩδοΫ 16ms
࠷దԽ 0ms
ϨΠΞτҎ֎ͷϩδοΫͦΜͳʹߴԽͰ͖ͳ͍ › Α΄Ͳॏ͍ॲཧΛॻ͍͍ͯͳ͍ݶΓɺ͢Ͱʹߴͳίʔυʹͳͬͯ ͍ΔՄೳੑߴ͍ › ϨΠΞτॲཧΛͲ͏ʹ͔͠ͳ͍ݶΓυϩοϓϑϨʔϜආ͚Β Εͳ͍ ࣮ࡍͷͱ͜Ζ
ϨΠΞτॲཧ͕ߴʹͳΕɺͦͷଞͷ ϩδοΫʹCPUϦιʔεΛඅ͢͜ͱ͕Ͱ ͖ΔΑ͏ʹͳΔ ϨΠΞτॲཧ ͦͷଞϩδοΫ 16ms ͜͏͍ͨ͠ 0ms ͦͷଞϩδοΫ
AutoLayoutΛΊͯΈΔ
ͱ͍͑ɺView.frame৮Γͨ ͘ͳ͍
ผͷϨΠΞτΤϯδϯ › facebook/Yoga (ւ֎൛PairsͰ༻த) › TextureGroup/Texture (ւ֎൛PairsͰ༻த) › mirego/PinLayout (ͪΐͬͱ৮ͬͯߟ͑த)
› linkedin/LayoutKit › mirego/PinLayout › mamaral/Neon
facebook/yoga *
Yoga › FacebookʹΑͬͯ։ൃ͞Ε͍ͯΔ › ඇৗʹߴͳΫϩεϓϥοτϑΥʔϜͳϨΠΞτΤϯδϯ › AutoLayoutͱൺֱͯ͠8ഒఔ͍ › https://github.com/layoutBox/FlexLayout#performance
Yoga › CSS Flexbox Layoutͱඇৗʹ͍ۙಈ࡞ͱࢦఆํࣜ › جຊUIStackViewͷverticalͱhorizontalΛΈ߹ΘͤͯϨΠΞ τ͢Δײ֮ › ίΞͱͳΔίʔυC++Ͱ3000ߦ΄Ͳ
› ؤுΕಡΊͦ͏Ͱ͢ɻ
Yoga › UIView.sizeThatFitsΛݺͼग़ͯ͠༰ʹԠͨ͡αΠζΛܾఆ͢Δ › ReactNativeͰΘΕ͍ͯΔ › ͜Εͭ·ΓɺReactNativeΞϓϦͷํ͕UIͷಈ࡞͕͍Մೳੑ ͕͋Δͱ͍͏͜ͱ
Yoga › APIͱͯ͠Objective-C༻ͳͷͰSwift͔Βͪΐͬͱ͍ͮΒ͍ › layoutBox/FlexLayoutͱ͍͏Swift༻ʹYogaΛϥοϓͨ͠ͷ͕͋ Δ › muukii/Mondrian͍ͬͯ͏ͷ࡞ͬͯΈͯΔ(ࠓࢭ·ͬͯΔ)
TextureGroup/Texture
Texture › ݩͷ໊AsyncDisplayKit › PinterestͷiOSΞϓϦͰશ໘తʹ༻͞Ε͍ͯΔɻ › PinterestͷૉΒ͍͠ಈ͖Textureͷύϫʔ
Texture › UIKitΛϥοϓ͢ΔܗͰUIύϑΥʔϚϯεΛ࠷େ·ͰҾ্͖͛ΔϥΠ ϒϥϦ › Objective-C++ʹΑΔ࣮
Texture › ϥΠϒϥϦར༻ऀUIKitΦϒδΣΫτΛૢ࡞͢ΔͷͰͳ͘ɺNodeͱ͍͏ΦϒδΣΫ τΛ௨ͯ͠UIΛૢ࡞͢Δɻ › NodeεϨουηʔϑͰ͋ΓɺόοΫάϥϯυεϨου͔ΒมߋՄೳ › Node -> UIViewͷల։Texture͕ߦ͏
› ඇಉظͰUIΛߋ৽͢Δ (AsyncʹDisplay͢Δ) › MainThread͕UIૢ࡞Ͱ͚͠Εߋ৽ΛݟૹΔ › UI͕ݻ·Βͳ͍ › ήʔϜΤϯδϯͬΆ͍ߟ͑ํ
Nodeͷछྨ › ASDisplayNode : NSObject › ASTextNode : ASDisplayNode -
UILabelͷΘΓ › ASImageNode : ASDisplayNode - UIImageViewͷΘΓ › ASButtonNode : ASDisplayNode - UIButtonͷΘΓ › ASCellNode : ASDisplayNode - UICollectionViewCell/UITableViewCellͷ ΘΓ › and more… Texture
ϨΠΞτ › ϨΠΞτNodeʹίʔυͰهड़ › CSS FlexboxͷۭؾײΛҾ͖ܧ͍Ͱ͓Γɺ͞ΒʹUIϨΠΞτʮ͋ Δ͋ΔʯʹରԠ͍͢͠هड़ํ๏͕༻ҙ͞Ε͍ͯΔɻ › ׳Εͯ͘ΔͱUIͷ։ൃͷޮ͕Α͘ͳΔ ›
ܭࢉYogaฒΈʹ͍͔ͱࢥΘΕΔ Texture
ڻ͘΄Ͳͷ࠷దԽ › ՄೳͳݶΓόοΫάϥϯυεϨουͰॲཧΛߦ͏ › UIͷϨεϙϯε͕࠷େԽ › UILabelUIImageViewΘΕͣʹϨΠϠʔʹϨϯμϦϯά › λοϓఆͷඞཁͷͳ͍ͷCALayerͱͯ͠දࣔ (layerBacking)
(UIViewΑΓϝϞϦফඅ͕͑ΒΕΔͨΊ) › όοΫάϥϯυͰϝϞϦղ์Λߦ͏Ωϡʔ (releaseʹCPUίετ͕͔͔ΔͨΊ) › Nodeʹهड़ͨ͠ϨΠΞτόοΫάϥϯυͰαΠζܭࢉ͕Մೳ › ConcurrentͰ࣮ߦ͞ΕΔͨΊɺNode͕࣋ͭσʔλ͕ଞεϨουʹґଘ͍ͯ͠ͳ͚ΕɺCPUͷίΞ͕ϑ ϧͰ͑Δ › iPhoneXͳΒ6ݸCellಉ࣌ʹܭࢉ Texture
TextureΛ࣮ͬͨͷงғؾ https://github.com/muukii/PlayTexture ࡉ͔͘આ໌͢Δͱ͕͘ͳͬͯ͠·͏ͷͰงғؾ͚ͩʹ͓͖ͯ͠·͢ɻ
None
None
UIKit class CardView : UIView { } ௨ৗ௨ΓUIKitͰViewΛ࡞ΔͳΒUIViewͷαϒ ΫϥεΛ࡞ͯ͠ViewΛ͍͖ͭͬͯ͘·͢
Texture // Textureʹͳ͚ͬͨͲModuleͷ໊લݹ͍·· import AsyncDisplayKit class CardNode : ASDisplayNode {
} TextureͰUIViewͷΘΓʹ ASDisplayNodeͷαϒΫϥεΛ࡞͠·͢ɻ
import AsyncDisplayKit class CardNode : ASDisplayNode { private let imageNode:
ASImageNode = .init() private let titleNode: ASTextNode = .init() private let detailNode: ASTextNode = .init() } ίϯϙʔωϯτΛఆٛ
class CardNode : ASDisplayNode { … init(image: UIImage, title: String,
detail: String) { super.init() titleNode.attributedText = NSAttributedString( string: title, attributes: […] ) detailNode.attributedText = NSAttributedString( string: detail, attributes: […] ) imageNode.image = image addSubnode(imageNode) addSubnode(titleNode) addSubnode(detailNode) // addSubnodeͷΘΓʹ `automaticallyManagesSubnodes = true` ͰΑ͍ } }
class CardNode : ASDisplayNode { … override func layoutSpecThatFits(_ constrainedSize:
ASSizeRange) -> ASLayoutSpec { // ⭐ ͜͜ʹϨΠΞτΛهड़͢Δ } }
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec(
ratio: 1.6, child: ASBackgroundLayoutSpec( child: ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] ) ), background: imageNode ) ) }
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec(
ratio: 1.6, child: ASBackgroundLayoutSpec( child: ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] ) ), background: imageNode ) ) }
let info = ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end,
alignItems: .start, children: [ titleNode, detailNode, ] ) Vertical
let body = ASBackgroundLayoutSpec( child: info, background: imageNode ) let
info = ASStackLayoutSpec(…
class CardNode : ASDisplayNode { … override func layoutSpecThatFits(_ constrainedSize:
ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec( ratio: 1.6, // ॎͷΧʔυͰදࣔ͢ΔͨΊbodyͷΞεϖΫτൺΛࢦఆ͢Δ child: body ) } }
let node = CardNode( image: UIImage(named: "sample")!, title: "Lorem Ipsum",
detail: "Lorem Ipsum……" ) view.addSubnode(node) let layout = node.calculateLayoutThatFits( ASSizeRange( min: .init(width: 0.0, height: 0), max: .init(width: 240.0, height: .infinity) ) ) node.frame.size = layout.size In ViewController ࣮ࡍɺ͜͏͍͏ίʔυ͋·Γॻ͔ͳ͍Ͱ͢ɻ CardNodeΛॳظԽ ViewController.viewʹaddSubnode nodeͷαΠζܭࢉΛߦ͏ αΠζͷRangeΛ༩͑Δ UIView.sizeThatFitsͷײ֮
None
let insetInfo = ASInsetLayoutSpec( insets: UIEdgeInsets( top: 8, left: 8,
bottom: 8, right: 8 ), child: info ) let info = ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] )
let body = ASBackgroundLayoutSpec( child: info, background: imageNode ) let
body = ASBackgroundLayoutSpec( child: insetInfo, background: imageNode )
None
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec { return ASRatioLayoutSpec(
ratio: 1.6, child: ASBackgroundLayoutSpec( child: ASInsetLayoutSpec( insets: .init(top: 8, left: 8, bottom: 8, right: 8), child: ASStackLayoutSpec( direction: .vertical, spacing: 8, justifyContent: .end, alignItems: .start, children: [ titleNode, detailNode, ] ) ), background: imageNode ) ) } શ෦·ͱΊΔͱ
DispatchQueue.global().async { let layout = node.calculateLayoutThatFits( ASSizeRange( min: .init(width: 0.0,
height: 0), max: .init(width: 240.0, height: .infinity) ) ) DispatchQueue.main.async { node.frame.size = layout.size } } όοΫάϥϯυͰαΠζܭࢉ
·ͱΊ › AutoLayoutॊೈͰڧྗͳϨΠΞτΤϯδϯ͕ͩɺ·ͩύϑΥʔϚϯε໘Ͱ՝ ͕͋Δɻ › ҰԠɺ࠷ۙͷiOSͰϨΠΞτॲཧΛগͳͤ͘͞Δೖ͖͍ͬͯͯΔ › UICollectionViewͷestimated~ͱ͔ › ݱঢ়ɺCPUͷΫϩοΫͷ৳ͼʹظͮ͠Β͍ͷͰɺUIύϑΥʔϚϯε্ͷ
ͨΊʹϚϧνεϨουʹΑΔΞϓϩʔν͕ඞਢʹͳͬͯ͘Δͣɻ › ͔͠͠ɺUIKitݱ࣌ͰϚϧνεϨουʹରԠ͍ͯ͠ͳ͍ɻ
·ͱΊ › ͜ͷݱঢ়ʹରͯ͠ɺFacebook,Instagram,PinterestͷΑ͏ͳαʔϏεϓϩμΫτʹ͓ ͍ͯAutoLayoutͷ༻Λආ͚͓ͯΓɺͦΕͧΕ͕UIύϑΥʔϚϯεΛ࠷େԽ͢ΔOSS Λެ։͍ͯ͠Δ › Pinterest - Texture ›
Facebook - ComponentKit, ReactNative, Texture › Instagram - IGListKit (ͪΐͬͱझࢫҧ͏͚Ͳ) › ͜ͷঢ়گʹରͯ͠ɺࠓޙApple͕औΔUIKitͷߟָ͕͑͠ΈͰ͢ɻAutoLayoutؤுͬ ͯཉ͍͠Ͱ͢Ͷʂ
Thank you