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
830
20190117_iOSLT_CBLinSwift.pdf
shtnkgm
0
120
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
さぁV100、メモリをお食べ・・・
nilpe
0
140
ふつうのFeature Flag実践入門
irof
7
3.9k
肥大化するレガシーコードに立ち向かうためのインターフェース分離と依存の逆転 / JJUG CCC 2026 Spring
hirokunimaeta
0
550
JavaDoc 再入門
nagise
1
340
net-httpのHTTP/2対応について
naruse
0
480
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
250
AI 時代のソフトウェア設計の学び方
masuda220
PRO
29
12k
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
680
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
570
The ROI of Quarkus for Spring Boot Applications
hollycummins
0
120
TSKaigi Night Talks 2026_TypeScriptでサプライチェーンの整合性を型に閉じ込める
geekplus_tech
0
350
技術記事、AIに書かせるか、自分で書くか? 〜それでも私が自分の手で書く理由〜 / #QiitaConference
jnchito
2
1.4k
Featured
See All Featured
Unsuck your backbone
ammeep
672
58k
AI: The stuff that nobody shows you
jnunemaker
PRO
8
710
Optimising Largest Contentful Paint
csswizardry
37
3.7k
Fantastic passwords and where to find them - at NoRuKo
philnash
52
3.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
239
140k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
How GitHub (no longer) Works
holman
316
150k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
180
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
27k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2k
Typedesign – Prime Four
hannesfritz
42
3.1k
Code Review Best Practice
trishagee
74
20k
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ϓϩτίϧͰ৭ͷߋ৽ॲཧΛڞ௨Խ
͓ΘΓ ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠