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
630
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
230
Property Wrappers
shtnkgm
0
220
パフォーマンス改善とユニットテスト
shtnkgm
4
1.4k
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
42
SwiftとFunctional Reactive Programming
shtnkgm
0
130
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
0
53
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
67
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
77
20171128_iOSLT_Swiftとイニシャライザ
shtnkgm
0
82
Other Decks in Programming
See All in Programming
try! Swift Tokyo 初参加報告LT
hinakko2
0
210
try! Swift Tokyo 2024 参加報告 / try! Swift Tokyo 2024 Report
hironytic
0
200
#phpcon_odawara オープン・クローズドなテストフィクスチャを求めて / open closed test fixtures
77web
3
220
PHPの次期バージョンはこの時期どうなっているのか - Internalsの開発体制について - PHPカンファレンス小田原
youkidearitai
PRO
1
190
PostmanでAPIの動作確認が楽になった話
h455h1
0
160
GitHub Actionsで泣かないためにやっておきたい設定 / Recommended GHA settings to avoid crying
pinkumohikan
3
520
DMMプラットフォームがTiDB Cloudを採用した背景
pospome
8
3.9k
Rubyでたのしむクリエイティブコーディング/Enjoy Creative coding with Ruby
chobishiba
1
170
Ruby Function Composition
bkuhlmann
1
330
if constexpr文はテンプレート世界のラムダ式である
faithandbrave
3
620
雑に思考を整理する技術と効能
konifar
58
28k
CQRS/ES avec Symfony, c’est (trop) bien !
jeremyfreeagent
1
640
Featured
See All Featured
GraphQLとの向き合い方2022年版
quramy
31
12k
In The Pink: A Labor of Love
frogandcode
138
21k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
658
120k
Fashionably flexible responsive web design (full day workshop)
malarkey
398
65k
Product Roadmaps are Hard
iamctodd
43
9.7k
Why You Should Never Use an ORM
jnunemaker
PRO
51
8.6k
Teambox: Starting and Learning
jrom
128
8.4k
Rebuilding a faster, lazier Slack
samanthasiow
72
8.2k
Fantastic passwords and where to find them - at NoRuKo
philnash
36
2.5k
The World Runs on Bad Software
bkeepers
PRO
61
6.7k
The Illustrated Children's Guide to Kubernetes
chrisshort
30
46k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
16
1.4k
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
͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ