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
20180710_iOSLT_iOSでDarkModeを実装する
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
shtnkgm
July 10, 2018
Programming
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
20180710_iOSLT_iOSでDarkModeを実装する
shtnkgm
July 10, 2018
More Decks by shtnkgm
See All by shtnkgm
Combine入門
shtnkgm
2
320
Property Wrappers
shtnkgm
0
370
Saliency Detection
shtnkgm
0
86
パフォーマンス改善とユニットテスト
shtnkgm
4
1.7k
iOSのコードベースレイアウト
shtnkgm
2
840
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
130
SwiftとFunctional Reactive Programming
shtnkgm
0
200
20180410_iOSLT_SwiftとProtocol-OrientedProgramming
shtnkgm
0
140
20180220_iOSLT_Swiftとオブジェクト間の通知のパターン
shtnkgm
0
170
Other Decks in Programming
See All in Programming
Snowflake Summitでの新機能 CoCo / CoWork / snowflake-summit-2026-overall-what-new-coco
tatsuhiro
1
210
エンジニアと一緒にテストコードの設計と実装を改善した話
mototakatsu
0
250
jQueryをバージョンアップする前に使いたいjQuery Migrate
matsuo_atsushi
0
640
「なぜそう決めたのか」を残し続ける仕組み ― Notion AI カスタムエージェント × Slack連携による設計判断の自動記録 - NIKKEI Tech Talk #47
niftycorp
PRO
0
250
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
820
アルゴリズムは何を圧縮しているのか ─ Haskell から育った「圧縮代数」というメンタルモデル
naoya
13
2.3k
AIエージェントで 変わるAndroid開発環境
takahirom
1
420
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.7k
AI駆動開発を妨げる技術的負債の解消アプローチ / ai-refactoring-approach
minodriven
17
8.6k
フィードバックで育てるAI開発
kotaminato
1
100
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
4.8k
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
3.1k
Featured
See All Featured
RailsConf 2023
tenderlove
30
1.5k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.8k
Amusing Abliteration
ianozsvald
1
220
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
670
Thoughts on Productivity
jonyablonski
76
5.2k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
1k
Why Your Marketing Sucks and What You Can Do About It - Sophie Logan
marketingsoph
0
180
Why You Should Never Use an ORM
jnunemaker
PRO
61
9.9k
Stop Working from a Prison Cell
hatefulcrawdad
274
21k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
220
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Groundhog Day: Seeking Process in Gaming for Health
codingconduct
0
240
Transcript
iOSͰDarkModeΛ࣮͢Δ 2018.7.10 iOSLT / Shota Nakagami (@shtnkgm)
Mojaveͷ৽ػೳDarkMode iOSͷαϙʔτͳ͍͚Ͳ࣮ͯ͠ΈΔ
DarkModeͬͯͲΜͳͷ?
None
None
DarkMode͔͍͍ͬ͜
DarkModeʹ͍͞͠
DarkMode
ࣗͰ࣮͢Δ
৭Λߟ͑Δ • ௨ৗ࣌ͱDarkModeͷ࣌ͲΜͳ৭ʹ͢Δ͔ • Human Interface GuidelinesʹMacOSͰͷDarkModeͷํ͋Γ • ͨͩ୯७ʹ໌Λస͢Εྑ͍Θ͚Ͱͳ͍ •
ݟ͍͢Α͏ʹDarkModeͰͷ৭ͷௐ͕ඞཁ • ۩ମతͳ৭ͷࢦఆGoogle Material Design͕ࢀߟʹͳΔ
৭ΛͱʹUIColorΛ֦ு͢Δ
UI DarkMode ௨ৗ ϝΠϯςΩετ ϗϫΠτʢα=100%ʣ ϒϥοΫʢα=87%ʣ αϒςΩετ ϗϫΠτʢα=70%ʣ ϒϥοΫʢα=54%ʣ DisabledςΩετ
ϗϫΠτʢα=50%ʣ ϒϥοΫʢα=38%ʣ ΞΫςΟϒΞΠίϯ ϗϫΠτʢα=100%ʣ ϒϥοΫʢα=54%ʣ ඇΞΫςΟϒΞΠίϯ ϗϫΠτʢα=38%ʣ ϒϥοΫʢα=50%ʣ σΟόΠμʔ άϨʔʢ#303030ʣ ϒϥοΫʢα=12%ʣ πʔϧόʔ άϨʔʢ#212121ʣ άϨʔʢ#F5F5F5ʣ Χʔυ άϨʔʢ#424242ʣ ϗϫΠτʢα=100%ʣ എܠ άϨʔʢ#303030ʣ άϨʔʢ#FAFAFAʣ
UIColorͷϓϥΠϕʔτExtensionͰෆಁ໌৭༻ͷมΛ࡞ private extension UIColor { static var gray050: UIColor {
return color("#FAFAFA") } static var gray100: UIColor { return color("#F5F5F5") } static var gray200: UIColor { return color("#EEEEEE") } static var gray300: UIColor { return color("#E0E0E0") } static var gray400: UIColor { return color("#BDBDBD") } static var gray500: UIColor { return color("#9E9E9E") } static var gray600: UIColor { return color("#757575") } static var gray700: UIColor { return color("#616161") } static var gray800: UIColor { return color("#424242") } static var gray850: UIColor { return color("#303030") } static var gray900: UIColor { return color("#212121") } }
UIColorͷϓϥΠϕʔτExtensionͰಁ໌৭༻ͷมΛ࡞ private extension UIColor { static var blackHalfTranslucent: UIColor {
return .init(white: 0, alpha: 0.5) } static var black012: UIColor { return .init(white: 1.00 - 0.12, alpha: 1) } static var black038: UIColor { return .init(white: 1.00 - 0.38, alpha: 1) } static var black050: UIColor { return .init(white: 1.00 - 0.50, alpha: 1) } static var black054: UIColor { return .init(white: 1.00 - 0.54, alpha: 1) } static var black070: UIColor { return .init(white: 1.00 - 0.70, alpha: 1) } static var black087: UIColor { return .init(white: 1.00 - 0.87, alpha: 1) } static var black100: UIColor { return .init(white: 1.00 - 1.00, alpha: 1) } static var whiteHalfTranslucent: UIColor { return .init(white: 1, alpha: 0.5) } static var white012: UIColor { return .init(white: 0.12, alpha: 1) } static var white038: UIColor { return .init(white: 0.38, alpha: 1) } static var white050: UIColor { return .init(white: 0.50, alpha: 1) } static var white054: UIColor { return .init(white: 0.54, alpha: 1) } static var white070: UIColor { return .init(white: 0.70, alpha: 1) } static var white087: UIColor { return .init(white: 0.87, alpha: 1) } static var white100: UIColor { return .init(white: 1.00, alpha: 1) } }
UIColorͷύϒϦοΫExtensionͰ෦৭ͷมΛ࡞ public extension UIColor { static var primary: UIColor {
return Config.shared.primaryColor } static var activeIcon: UIColor { return isDarkTheme ? .white100 : .black054 } static var inactiveIcon: UIColor { return isDarkTheme ? .white038 : .black050 } static var primaryText: UIColor { return isDarkTheme ? .white100 : .black087 } static var secondaryText: UIColor { return isDarkTheme ? .white070 : .black054 } static var disabledText: UIColor { return isDarkTheme ? .white050 : .black038 } static var linkText: UIColor { return .flatSkyBlue() } static var dividers: UIColor { return isDarkTheme ? .gray850 : .black012 } static var statusBar: UIColor { return isDarkTheme ? .black100 : .gray300 } static var appBar: UIColor { return isDarkTheme ? .gray900 : .gray100 } static var highlightedAppBar: UIColor { return isDarkTheme ? .gray800 : .gray200 } static var background: UIColor { return isDarkTheme ? .gray850 : .gray050 } static var card: UIColor { return isDarkTheme ? .gray800 : .white100 } static var highlightedCard: UIColor { return isDarkTheme ? .gray850 : .gray100 } }
৭Λࢦఆ͢Δ backgroundColor = .card mainLabel.textColor = .primaryText settingSwitch.onTintColor = .primary
ΞΠίϯը૾Ͳ͏͢Δʁ
UIImageΛUIColorͰృΕΔΑ͏ʹ͢Δ
public extension UIImage { public func image(withTint color: UIColor) ->
UIImage { let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height) UIGraphicsBeginImageContextWithOptions(rect.size, false, 0) guard let context: CGContext = UIGraphicsGetCurrentContext(), let cgImage = cgImage else { return UIImage() } context.scaleBy(x: 1, y: -1) context.translateBy(x: 0, y: -self.size.height) context.clip(to: rect, mask: cgImage) context.setFillColor(color.cgColor) context.fill(rect) guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return UIImage() } UIGraphicsEndImageContext() return image } }
let iconImage = UIImage(named: "icon").image(withTint: .activeIcon)
image(withTint: )OSSͷta1n/Swi3ExtensionsͰར༻Մ
ࣗcontribu)onͯ͠·͢
ΊͰͨ͠ΊͰͨ͠
ΊͰͨ͠ΊͰͨ͠
ϞʔυΓସ͑࣌ʹ৭ͷมߋ͕ඞཁ DarkMode⁶௨ৗ
͜Ε͕Γ͍ͨ ΈΜͳʙ৭Λߋ৽ͯ͠ʙ
௨ઌ͕nݸͷ௨ͷΈͱ͍͑ʁ
No#fica#onCenter ࢀߟ: shtnkgm / Swi.ͱΦϒδΣΫτؒͷ௨ͷύλʔϯ
࣮֓ཁ 1. ֤ViewͰ௨Λߪಡ͓ͯ͘͠ 2. Ϟʔυͷมߋ࣌ʹNo*fica*onCenterͰ௨ 3. ֤ViewͰ௨Λड͚औΔ 4. ֤ViewͰ৭Λߋ৽
֤ViewͰड৴ॲཧΛॻ͘ͷ໘ public extension Notification.Name { static let styleUpdated = Notification.Name("styleUpdated")
} class HogeView { init() { let center = NotificationCenter.default center.addObserver(self, selector: #selector(updateStyle), name: .styleUpdated, object: nil) updateStyle() } @objc func updateStyle() { backgroundColor = .card } }
ϓϩτίϧͰॲཧΛڞ௨Խ
StyleUpdatable
public protocol StyleUpdatable: class { /// ௨Λղআ͢Δ߹ObserverΛอ࣋͢Δඞཁ͋Γ var updateStyleObserver: NSObjectProtocol?
{ get set } /// ৭ͷߋ৽ॲཧඞͣupdateStyleͱ͍͏໊લͷϝιουͰߦ͏ func updateStyle() }
public extension StyleUpdatable { /// updateStyleObserverΛҙ࣮ͱ͢ΔͨΊͷσϑΥϧτ࣮ var updateStyleObserver: NSObjectProtocol? {
get { return nil } set { } } /// ߪಡ & updateStyle()Λ࣮ߦ func observeAndUpdateStyle() { updateStyle() let center = NotificationCenter.default updateStyleObserver = center.addObserver(forName: .styleUpdated, object: nil, queue: nil) { [weak self] _ in self?.updateStyle() } } }
class HogeView: StyleUpdatable { init() { observeAndUpdateStyle() } // StyleUpdatableʹΑΓ࣮͕ڧ੍͞ΕΔ
func updateStyle() { backgroundColor = .card } }
ద༻αϯϓϧ ͡ͿΜͷΞϓϦͰಋೖ
None
None
None
None
ͦΕͬΆ͘ͳͬͨ
·ͱΊ • DarkModeͱ௨ৗ࣌ͷ৭Λߟ͑Δ • UIColorΛ֦ுͯ͠ɺDarkMode͔Ͳ͏͔Ͱذ (֤ViewDarkMode͔Ͳ͏͔Λߟྀ͠ͳͯ͘ྑ͍) • ΞΠίϯUIImageΛUIColorͰృΕΔΑ͏ʹ͢Δ • StyleUpdatableϓϩτίϧͰ৭ͷߋ৽ॲཧΛڞ௨Խ
͓ΘΓ ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠