Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
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
60
パフォーマンス改善とユニットテスト
shtnkgm
4
1.7k
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
100
SwiftとFunctional Reactive Programming
shtnkgm
0
180
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
0
98
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
120
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
140
Other Decks in Programming
See All in Programming
[堅牢.py #1] テストを書かない研究者に送る、最初にテストを書く実験コード入門 / Let's start your ML project by writing tests
shunk031
12
7k
複数人でのCLI/Infrastructure as Codeの暮らしを良くする
shmokmt
5
2.2k
リリース時」テストから「デイリー実行」へ!開発マネージャが取り組んだ、レガシー自動テストのモダン化戦略
goataka
0
110
宅宅自以為的浪漫:跟 AI 一起為自己辦的研討會寫一個售票系統
eddie
0
480
251126 TestState APIってなんだっけ?Step Functionsテストどう変わる?
east_takumi
0
300
connect-python: convenient protobuf RPC for Python
anuraaga
0
370
Developing static sites with Ruby
okuramasafumi
0
190
スタートアップを支える技術戦略と組織づくり
pospome
8
15k
tsgolintはいかにしてtypescript-goの非公開APIを呼び出しているのか
syumai
5
1.9k
MAP, Jigsaw, Code Golf 振り返り会 by 関東Kaggler会|Jigsaw 15th Solution
hasibirok0
0
220
【CA.ai #3】ワークフローから見直すAIエージェント — 必要な場面と“選ばない”判断
satoaoaka
0
230
20251127_ぼっちのための懇親会対策会議
kokamoto01_metaps
2
420
Featured
See All Featured
How STYLIGHT went responsive
nonsquared
100
5.9k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
Facilitating Awesome Meetings
lara
57
6.7k
Statistics for Hackers
jakevdp
799
230k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.4k
How GitHub (no longer) Works
holman
316
140k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
Making Projects Easy
brettharned
120
6.5k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
700
Mobile First: as difficult as doing things right
swwweet
225
10k
Reflections from 52 weeks, 52 projects
jeffersonlam
355
21k
Large-scale JavaScript Application Architecture
addyosmani
514
110k
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
͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ