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
shtnkgm
July 10, 2018
Programming
130
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
330
Property Wrappers
shtnkgm
0
370
Saliency Detection
shtnkgm
0
89
パフォーマンス改善とユニットテスト
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
S3 を使うアプリケーションをローカル完結で動かすことに全力を注いでみた / Running S3 Apps Offline
contour_gara
0
580
MySQLとPostgreSQLって何が違うの?
akagami
0
130
楽しそうなつよつよエンジニアと目が死んでる僕/A brilliant engineer having a blast, and dead-eyed me.
3l4l5
2
240
go-spidermonkeyでAIエージェントのCode Modeを実装する
syumai
1
700
メールのエイリアス機能を履き違えない
isshinfunada
0
250
いまどきの Codex で開発する visionOS アプリの開発スタイルについて
karad
0
160
AI Engineeringは、AIプロダクトだけのものか? 〜AIがソフトウェアを作る時代の新しい当たり前〜 / No AI in your product. AI Engineering in your development.
rkaga
5
510
VibeCodingからAgenticWorkflowへ
starfish719
0
780
Detecting Compromised CI with eBPF and Cilium Tetragon
lizrice
0
250
jsmini JavaScript Engine を作ってみた話
yosuke_furukawa
PRO
0
350
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
280
AI Readyの正体はデータマネジメントだ メダリオン2.0の最前線
freee
PRO
0
360
Featured
See All Featured
The Power of CSS Pseudo Elements
geoffreycrofte
82
6.5k
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Embracing the Ebb and Flow
colly
88
5.1k
Ethics towards AI in product and experience design
skipperchong
2
350
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
540
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
420
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
350
30 Presentation Tips
portentint
PRO
1
380
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2.1k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
508
140k
YesSQL, Process and Tooling at Scale
rocio
174
15k
How STYLIGHT went responsive
nonsquared
100
6.2k
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ϓϩτίϧͰ৭ͷߋ৽ॲཧΛڞ௨Խ
͓ΘΓ ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠