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
iOSのコードベースレイアウト
Search
shtnkgm
January 31, 2019
Programming
2
780
iOSのコードベースレイアウト
Mobile Act TOKYO #5
https://mobileact.connpass.com/event/114398
shtnkgm
January 31, 2019
Tweet
Share
More Decks by shtnkgm
See All by shtnkgm
Combine入門
shtnkgm
2
290
Property Wrappers
shtnkgm
0
350
Saliency Detection
shtnkgm
0
55
パフォーマンス改善とユニットテスト
shtnkgm
4
1.7k
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
97
SwiftとFunctional Reactive Programming
shtnkgm
0
180
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
0
96
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
120
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
130
Other Decks in Programming
See All in Programming
イベントストーミングのはじめかた / Getting Started with Event Storming
nrslib
1
340
MCPサーバー「モディフィウス」で変更容易性の向上をスケールする / modifius
minodriven
8
1.4k
レイトレZ世代に捧ぐ、今からレイトレを始めるための小径
ichi_raven
0
250
ノーコードからの脱出 -地獄のデスロード- / Escape from Base44
keisuke69
0
680
「10分以内に機能を消せる状態」 の実現のためにやっていること
togishima
1
270
PHPライセンス変更の議論を通じて学ぶOSSライセンスの基礎
matsuo_atsushi
0
140
Agentに至る道 〜なぜLLMは自動でコードを書けるようになったのか〜
mackee
4
650
Flutterアプリ運用の現場で役立った監視Tips 5選
ostk0069
1
360
Rails Girls Sapporo 2ndの裏側―準備の日々から見えた、私が得たもの / SAPPORO ENGINEER BASE #11
lemonade_37
2
110
2025 컴포즈 마법사
jisungbin
0
100
Swift Concurrency 年表クイズ
omochi
3
230
Designing Repeatable Edits: The Architecture of . in Vim
satorunooshie
0
270
Featured
See All Featured
GitHub's CSS Performance
jonrohan
1032
470k
Making the Leap to Tech Lead
cromwellryan
135
9.6k
For a Future-Friendly Web
brad_frost
180
10k
Statistics for Hackers
jakevdp
799
220k
Faster Mobile Websites
deanohume
310
31k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
48
9.8k
Building Flexible Design Systems
yeseniaperezcruz
329
39k
How To Stay Up To Date on Web Technology
chriscoyier
791
250k
The Pragmatic Product Professional
lauravandoore
36
7k
Rails Girls Zürich Keynote
gr2m
95
14k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
Transcript
iOSͷίʔυϕʔεϨΠΞτ Mobile Act TOKYO #5 @shtnkgm
iOS Engineer Shota Nakagami @shtnkgm
͢͜ͱ • iOSͷUIϨΠΞτख๏ͷൺֱ • ίʔυϕʔεϨΠΞτ Tips
UIͷϨΠΞτख๏ • ϓϩάϥϜͰهड़ʢίʔυϕʔεʣ • Storyboard • Interface BuilderʢXIBʣ
ͦΕͧΕͷಛ
StoryboardͱXIBͷಛ
ྑ͍ͱ͜Ζ • ෳͷը໘αΠζͰذɺݟ͑ํνΣοΫʢSize Classesʣ • Ϗϧυલʹ੩తͳ੍ͷݕࠪ • Storyboardͷ߹Segue͕͑Δ
ΠϚΠνͳͱ͜Ζ • ίϐϖɺΧελϜΫϥεԽͳͲͷ࠶ར༻ɾमਖ਼͕ͮ͠Β͍ • XMLͳͷͰίϯϑϦΫτͷղফɺίʔυϨϏϡʔ͕͍͠ • GUIͰΆͪΆͪ͠ͳ͍ͱԿ͕ઃఆͯ͋͠Δͷ͔ٯʹΘ͔Βͳ͍
ίʔυϕʔεϨΠΞτͷಛ
ྑ͍ͱ͜Ζ • ίϐϖίʔυஔͳͲͰεϐʔσΟʹ࠶ར༻ɾमਖ਼͕Մೳ • ίϯϑϦΫτͷղফϨϏϡʔ͕͍͢͠ • Կ͕ઃఆͯ͋͠Δͷ͔Ұཡੑ͕͋Δ
ΠϚΠνͳͱ͜Ζ • UIKitͷϓϩύςΟϥΠϑαΠΫϧʹؔ͢Δ͕ࣝඞཁ • ࣮ߦ͢Δ·Ͱݟ͑ํ૾
Dependency Injectionͷҧ͍
Storyboard // NG: ίϯετϥΫλΠϯδΣΫγϣϯෆՄ let viewController = ViewController(dependency: Dependency()) //
OK: ϓϩύςΟΠϯδΣΫγϣϯʹͳΒՄ let storyboard = UIStoryboard(name: "ViewController", bundle: nil) let viewController = storyboard.instantiateInitialViewController() viewController.dependency = Dependency()
XIB / ίʔυϕʔε class ViewController: UIViewController { let dependency: Dependency
init(dependency: Dependency) { self.dependency = dependency super.init(nibName: nil, bundle: nil) } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
ൺֱ߲ Storyboard XIB ίʔυϕʔε ➡ Segue͕͑Δ ✅ # GUIͰݟͯΘ͔Δ ✅
✅ $ αΠζذ͕༰қ ✅ ✅ % ੩తνΣοΫ ✅ ✅ &ίϯετϥΫλDI ✅ ✅ ♻ ࠶ར༻ੑ ✅ ( ίϯϑϦΫτੑ ✅ ) ϨϏϡʔ͢͠͞ ✅
I ! Code-based Laout
ίʔυϕʔεϨΠΞτTipsʢ6ͭʣ
1. Initialization Closure
class ViewController: UIViewController { let priceLabel = UILabel() // એݴ
let imageView = UIImageView() // એݴ override func viewDidLoad() { super.viewDidLoad() priceLabel.numberOfLines = 2 // ϓϩύςΟઃఆ priceLabel.textColor = .red // ϓϩύςΟઃఆ priceLabel.font = .boldSystemFont(ofSize: 14) // ϓϩύςΟઃఆ imageView.contentMode = .scaleAspectFill // ϓϩύςΟઃఆ imageView.clipsToBounds = true // ϓϩύςΟઃఆ imageView.layer.cornerRadius = 4 // ϓϩύςΟઃఆ // addSubview, AutoLayout... } }
class ViewController: UIViewController { let priceLabel: UILabel = { let
label = UILabel() label.numberOfLines = 2 label.textColor = .red label.font = .boldSystemFont(ofSize: 14) return label }() let imageView: UIImageView = { let view = UIImageView() view.contentMode = .scaleAspectFill view.clipsToBounds = true view.layer.cornerRadius = 4 return view }() override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }
2. Then
class ViewController: UIViewController { let priceLabel: UILabel = { //
ܕΞϊςʔγϣϯ let label = UILabel() // ϩʔΧϧείʔϓͰͷ໋໊ label.numberOfLines = 2 // label label.textColor = .red // label label.font = .boldSystemFont(ofSize: 14) // label return label // ੜͨ͠Πϯελϯεͷreturn }() let imageView: UIImageView = { // ܕΞϊςʔγϣϯ let view = UIImageView() // ϩʔΧϧείʔϓͰͷ໋໊ view.contentMode = .scaleAspectFill // view view.clipsToBounds = true // view view.layer.cornerRadius = 4 // view return view // ੜͨ͠Πϯελϯεͷreturn }() override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }
class ViewController: UIViewController { let priceLabel = UILabel().then { $0.numberOfLines
= 2 $0.textColor = .red $0.font = .boldSystemFont(ofSize: 14) } let imageView = UIImageView().then { $0.contentMode = .scaleAspectFill $0.clipsToBounds = true $0.layer.cornerRadius = 4 } override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }
Thenͷ࣮ public protocol Then {} extension Then where Self: AnyObject
{ public func then(_ block: (Self) throws -> Void) rethrows -> Self { try block(self) return self } }
3. ΧελϜΫϥε
ΧελϜΫϥεͰ࠶ར༻ੑΛߴΊɺΑΓγϯϓϧʹ class ViewController: UIViewController { let priceLabel = PriceLabel() //
ΧελϜΫϥεԽ let imageView = ItemImageView() // ΧελϜΫϥεԽ override func viewDidLoad() { super.viewDidLoad() // addSubview, AutoLayout... } }
4. lazy var
private let captureButton = CaptureButton().then { $0.onTapped = { [weak
self] in // selfࢀর͍ͨ͠ self?.camera.capture() // selfࢀর͍ͨ͠ } }
private let captureButton = CaptureButton().then { $0.onTapped = { [weak
self] in // ίϯύΠϧΤϥʔ self?.camera.capture() // ίϯύΠϧΤϥʔ } }
lazy varͰॳظԽԆɺselfΛࢀরՄʹ private lazy var captureButton = CaptureButton().then { $0.onTapped
= { [weak self] in self?.camera.capture() // OK } }
5. SnapKit / PureLayout
NSLayoutAnchorʢiOS9ʙʣ button.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true button.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true button.topAnchor.constraintEqualToAnchor(view.topAnchor).active = true
button.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor).active = true
!
SnapKit / PureLayout // SnapKit button.snp.makeConstraints { $0.edges.equalToSuperview() } //
PureLaout button.autoPinEdgesToSuperviewEdges()
// ಡΈ͍͢ button.snp.makeConstraints { $0.center.equalToSuperview() // Ϗϡʔͷத৺ʹ $0.size.equalTo(CGSize(width: 64, height:
64)) // αΠζࢦఆ } // Safe AreaʹϨΠΞτΛషΓ͍͢ tableView.snp.makeConstraints { $0.top.bottom.equalTo(view.safeAreaLayoutGuide) // ্ԼSafe Areaʹ $0.leading.trailing.equalToSuperview() // ࠨӈϏϡʔʹ }
☺
6. UIStackView
UIStackViewͰϨΠΞτ͢Δ stackView.addArrangedSubview(label) stackView.addArrangedSubview(imageView) stackView.addArrangedSubview(button) label.snp.makeConstraints { $0.height.equalTo(20) } button.snp.makeConstraints {
$0.height.equalTo(60) }
·ͱΊ • ίʔυϕʔεϨΠΞτͰTipsΛ͑؆͔ܿͭεϐʔσΟ • Ͳͷख๏Ͱ͖ΔΑ͏ʹ͓͖ͯ͠ɺ͍͚͍ͨ
αϯϓϧίʔυ github.com/shtnkgm/ iOSUILayoutMethods
͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ