Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Android DarkTheme 코드랩

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

Android DarkTheme 코드랩

Avatar for Sungyong An

Sungyong An

July 19, 2019
Tweet

More Decks by Sungyong An

Other Decks in Programming

Transcript

  1. • Android Q
 Settings > Display > Dark Theme
 


    ( 'যف਍ ప݃' QuickSettingب ୶оؽ ) • Android P
 Settings > System > Developer options > Night mode
 
 ( ࢖ࢿ ױ݈਷ 'ঠр ݽ٘' QuickSetting ઁҕ ) OS Setting New
 in Q
  2. New
 in Q • জਸ ׮௼ ప݃۽ ੗ز ߸ജೞח ӝמ

    • API 29 ( ) ীࢲ݅ ࢎਊоמ ForceDark
  3. • ݽٚ জী force-darkܳ ੸ਊೞח ѐߊ੗ ݽ٘ • Android Q

    Settings > System > Developer options > Override force-dark Override ForceDark • ೞ૑݅ Q Beta4ࠗఠ ز੘ೞ૑ ঋח׮. $ F O R C E D A R K
  4. • জ ప݃੄ forceDarkAllowed ࣘࢿਸ true۽ ࢸ੿ೞݶ ഝࢿചػ׮.
 
 


    
 • ױ, Light ప݃݅ ForceDarkо ੸ਊؼ ࣻ ੓׮. Enable ForceDark F O R C E D A R K <style name="AppTheme" parent="@style/Theme.MaterialComponents.Light> <item name="android:forceDarkAllowed">true</item> </style> <style name="Theme.AppCompat.Light" parent="..."> <item name="isLightTheme">true</item> </style>
  5. • ࠗ࠙੸ਵ۽ ForceDarkܳ ࠺ഝࢿചೡ ࣻب ੓׮. <!-- For Layout XML

    --> <View android:forceDarkAllowed="false" /> // For Kotlin view.isForceDarkAllowed = false // For Java view.setForceDarkAllowed(false) Disable ForceDark (Partially) F O R C E D A R K
  6. CodeLab • Android Studio 3.4 ੉࢚ • API 21 ੉࢚

    Emulator / ױ݈ӝ (STEP7਷ Q ೙ਃ) • Kotlin • DataBinding ળ࠺ $ git clone https://github.com/fornewid/Android-DarkTheme-CodeLab
  7. CodeLab • ঠр/઱р ݽ٘о ߸҃غ૑ ঋח ޙઁ • AppCompatDelegate API

    ഐ୹ द,
 AppCompatActivityо ੤द੘غ૑ ঋח׮. Step 1. CodeLab
  8. • Android 4.0 (API14) ੉࢚ ૑ਗ • AppCompat 1.1.0ীࢲ ز੘

    ѐࢶ • Night Modeо ߸҃غݶ AppCompatActivityо ੗زਵ۽ ੤द੘ػ׮. AppCompat: Night Mode
  9. • MODE_NIGHT_YES
 ೦࢚ যنѱ ಴द • MODE_NIGHT_NO
 ೦࢚ ߋѱ ಴द

    • MODE_NIGHT_FOLLOW_SYSTEM
 दझమ ࢸ੿ী ٮۄ ߸҃ • MODE_NIGHT_AUTO_BATTERY
 ੺੹ݽ٘ীࢲ যنѱ ಴द Modes N I G H T M O D E App
 Compat 1.1.0 API21 ↑
  10. • ঠрݽ٘ܳ ࢸ੿ೞח ߑߨ੉ 2о૑ ੓׮. Set night mode N

    I G H T M O D E // AppCompatDelegate.java public abstract void setLocalNightMode(@NightMode int mode); public static void setDefaultNightMode(@NightMode int mode) { ... } • ଵҊ: ч੉ in-memoryী ੷੢غ޲۽, ߹ب۽ чਸ ੷੢/ࠂҳ ೧ঠ ೠ׮.
  11. • Configuration ੿ࠁ۽ ঠрݽ٘ ੸ਊ ৈࠗܳ ഛੋೡ ࣻ ੓׮. Get

    night mode N I G H T M O D E fun isDarkTheme(config: Configuration): Boolean { return config.uiMode and // andח &৬ زੌ Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES }
  12. • Activityܳ ੤द੘ೞ૑ ঋҊ, ࣻزਵ۽ DarkThemeܳ ੸ਊೡ ࣻب ੓׮. Manual

    Night Mode N I G H T M O D E <activity android:name=".MainActivity" android:configChanges="uiMode" /> class MainActivity : AppCompatActivity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) val isDarkTheme: Boolean = isDarkTheme(newConfig) ... UI সؘ੉౟ ... } }
  13. CodeLab • start/build.gradle S T E P 1 Use AppCompat

    1.1.0 (1/1) //TODO: STEP1 - Use AppCompat 1.1.0 implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
  14. CodeLab • DarkTheme.kt (Pre-defined) S T E P 1 Done!

    fun apply(enabled: Boolean = false) { val nightMode = if (enabled) { AppCompatDelegate.MODE_NIGHT_YES } else { AppCompatDelegate.MODE_NIGHT_NO } AppCompatDelegate.setDefaultNightMode(nightMode) }
  15. • L OS ੉੹ীח ӝࠄ ప݃о Dark Theme৓׮. Dark Theme

    Dark Theme: <style name="Theme.DeviceDefault" /> Light Theme: <style name="Theme.DeviceDefault.Light" />
  16. • AppCompatীࢲب Dark Themeܳ ઁҕೠ׮. Dark Theme Dark Theme: <style

    name="Theme.AppCompat"/> Light Theme: <style name="Theme.AppCompat.Light"/>
  17. • Night Modeীࢲח -night resource qualifierо ഝࢿചػ׮. • '-night' ಫ؊ী

    ܻࣗझܳ ୶о೧ঠ ೠ׮. • ৘) values-night, raw-night ١١ '-night' Resource Qualifier Link: https://developer.android.com/guide/topics/resources/providing-resources#AlternativeResources <!-- values/colors.xml --> <color name=“colorCustom">#000000</color> <!-- values-night/colors.xml --> <color name=“colorCustom">#ffffff</color>
  18. • ⚠ Resource Qualifier ਋ࢶࣽਤܳ ઱੄೧ঠ ೠ׮. '-night' Resource Qualifier

    res/drawable-hdpi/ic_example.png res/drawable-night-hdpi/ic_example.png res/drawable-land/ic_example.png res/drawable-land-night/ic_example.png
  19. CodeLab • res/values-night/styles.xml S T E P 2 Declare '-night'

    resources (1/3) <!-- TODO: STEP2 - Declare '-night' resources --> <style name="AppTheme" parent="Theme.AppCompat.NoActionBar"> ... </style> <style name="AppTheme.Splash"> ... </style> <style name="AppTheme.Github" parent="Theme.AppCompat" />
  20. CodeLab • res/values-night/colors.xml S T E P 2 Declare '-night'

    resources (2/3) <!-- TODO: STEP2 - Declare '-night' resources --> <color name="colorPrimary">#121212</color> <color name="colorPrimaryDark">#000000</color> <color name="colorAccent">#00c300</color> <color name="colorBackground">#202020</color> ... <color name="colorOnError">#202020</color>
  21. CodeLab • Splash ۽Ҋ ੉ܴ ߸҃ S T E P

    2 Declare '-night' resources (3/3) Before: res/drawable-night/ic_logo_soup_night.png After: res/drawable-night/ic_logo_soup.png
  22. • খࢲ ࠄ Modeܳ ੉ਊೞৈ Drawableী ࢝ઑܳ ੑ൧ ࣻ ੓׮.

    (ӝࠄ: SRC_IN) • ColorStateList۽ Stateful Tintب оמೞ׮. • API 21 ࠗఠ ୶оغ঻૑݅, Compat APIо ઁҕػ׮. • DrawableCompat • VectorDrawableCompat Tint
  23. • Drawable XMLীࢲ android:tint ࣘࢿਸ ࢎਊೡ ࣻ ੓׮. Tinting Drawables

    <!-- res/drawable/shape.xml --> <shape android:tint="@color/btn_background"> <solid android:color="@color/white" /> </shape> <!-- res/drawable/vector.xml --> <vector android:tint="@color/btn_background"> <path android:fillColor="@color/white" /> </vector>
  24. • Viewب Tint APIо ઁҕػ׮. Tinting Views <ImageView android:tint="@color/btn_icon" />

    <View android:backgroundTint="@color/btn_background" /> imageView.setImageTintList(ColorStateList) view.setBackgroundTintList(ColorStateList) ImageViewCompat.setImageTintList(view, ColorStateList) ViewCompat.setBackgroundTintList(view, ColorStateList)
  25. CodeLab • res/drawable/ic_round_favorite_off.xml S T E P 3 Tinting icons

    (1/2) <!-- TODO: STEP3 - Tinting icons --> <vector android:width="24dp" android:height="24dp" android:tint="@color/colorIcon">
  26. CodeLab • res/drawable/ic_round_error_outline.xml S T E P 3 Tinting icons

    (2/2) <!-- TODO: STEP3 - Tinting icons --> <vector android:width="24dp" android:height="24dp" android:tint="@color/colorOnError">
  27. • Animation ࢸ੿ೡ ٸ, زੌ ܻࣗझ IDח সؘ੉౟غ૑ ঋח ੉गо

    ੓׮. Lottie Issue // LottieComposition.java private static String rawResCacheKey(@RawRes int resId) { return "rawRes_" + resId; } Link: https://github.com/airbnb/lottie-android/issues/1305
  28. CodeLab • res/layout/home_card_moop.xml S T E P 4 Set 'Lottie'

    dynamically (1/2) <!--TODO: STEP4 - Set 'Lottie' animation dynamically --> <import type="soup.codelab.darktheme.R" /> <com.airbnb.lottie.LottieAnimationView android:id="@+id/favoriteButton" ... app:lottie_rawResDay="@{R.raw.ic_lottie_favorite_day}" app:lottie_rawResNight="@{R.raw.ic_lottie_favorite_night}" />
  29. CodeLab • LottieBindingAdapter.kt S T E P 4 Set 'Lottie'

    dynamically (2/2) @BindingAdapter("lottie_rawResDay", "lottie_rawResNight") fun setAnimationAsync(view: LottieAnimationView, @RawRes dayRawRes: Int, @RawRes nightRawRes: Int) { if (DarkTheme.isEnabled(view.context)) { view.setAnimation(nightRawRes) } else { view.setAnimation(dayRawRes) } }
  30. CodeLab Step 5. <!-- res/values/colors.xml --> <color name="colorPrimary" >#FF00c300</color> <color

    name="colorPrimaryDark" >#FF00b300</color> <color name="colorAccent" >#FF00c300</color> <color name="colorBackground" >#FFffffff</color> <color name="colorText" >#FF000000</color> <color name="colorIcon" >#FF000000</color> <color name="colorSurface" >#FFeeeeee</color> <color name="colorTagBackground">#1A000000</color> <color name="colorTagText" >#FF121212</color> <color name="colorDivider" >#1F000000</color> <color name="colorBorder" >#33000000</color> <color name="colorName" >#dd000000</color> <color name="colorError" >#FFee4b4b</color> <color name="colorOnError" >#FFffffff</color> <!-- res/values/colors.xml --> <color name="colorPrimary" >#FF00c300</color> <color name="colorPrimaryDark" >#FF00b300</color> <color name="colorAccent" >#FF00c300</color> <color name="colorBackground" >#FFffffff</color> <color name="colorText" >#FF000000</color> <color name="colorIcon" >#FF000000</color> <color name="colorSurface" >#FFeeeeee</color> <color name="colorTagBackground">#1A000000</color> <color name="colorTagText" >#FF121212</color> <color name="colorDivider" >#1F000000</color> <color name="colorBorder" >#33000000</color> <color name="colorName" >#dd000000</color> <color name="colorError" >#FFee4b4b</color> <color name="colorOnError" >#FFffffff</color> • ҙܻೞח Colorо ݆ই૑ח ޙઁ • Color Attributeܳ ੉ਊೞৈ
 Ӓܛ ױਤ۽ ҙܻೡ ࣻ ੓׮.
  31. • android:alpha attribute੉ ನೣػ ColorStateList ܻࣗझܳ ੍ਸ ٸ,
 API 23

    ੉ೞ ߡ੹ীࢲח AppCompat APIܳ ࢎਊ೧ঠ ೤פ׮. ColorStateList AppCompatResources.getColorStateList(context, R.color.divider)
  32. CodeLab • res/values/attrs.xml S T E P 5 Use color

    attribute (1/5) <!-- TODO: STEP5 - Use color attribute --> <attr name="colorOnBackground" format="color" />
  33. CodeLab • res/values/styles.xml S T E P 5 Use color

    attribute (2/5) <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> ... <!-- TODO: STEP5 - Use color attribute --> <item name="colorOnBackground">@android:color/black</item> </style>
  34. CodeLab • res/values-night/styles.xml S T E P 5 Use color

    attribute (3/5) <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> ... <!-- TODO: STEP5 - Use color attribute --> <item name="colorOnBackground">@android:color/white</item> <style>
  35. CodeLab • res/color/divider.xml S T E P 5 Use color

    attribute (4/5) <selector> <!-- TODO: STEP5 - Use color attribute --> <item android:alpha="0.1" android:color="?colorOnBackground" /> </selector>
  36. CodeLab • res/layout/home_card_soup.xml • res/layout/home_card_moop.xml S T E P 5

    Use color attribute (5/5) <!-- TODO: STEP5 - Use color attribute --> <ImageView android:id="@+id/divider" ... android:background="#ffffff" app:backgroundTint="@color/divider" />
  37. • AppCompatীࢲ DayNight themeܳ ઁҕೠ׮. DayNight Theme values/theme.xml <style name="Theme.AppCompat.DayNight"

    parent="Theme.AppCompat.Light" /> values-night/theme.xml <style name="Theme.AppCompat.DayNight" parent="Theme.AppCompat" />
  38. • AppCompatীࢶ ThemeOverlayب DayNight themeܳ ઁҕೠ׮. DayNight Theme values/theme.xml <style

    name="ThemeOverlay.AppCompat.DayNight" parent="ThemeOverlay.AppCompat.Light"/> values-night/theme.xml <style name="ThemeOverlay.AppCompat.DayNight" parent="ThemeOverlay.AppCompat.Dark"/>
  39. • MDCীب DayNight themeܳ ઁҕೠ׮. DayNight Theme values/theme.xml <style name="Theme.MaterialComponents.DayNight"

    parent="Theme.MaterialComponents.Light" /> values-night/theme.xml <style name="Theme.MaterialComponents.DayNight" parent="Theme.MaterialComponents" />
  40. • ೞ૑݅ MDCী ThemeOverlayח DayNight themeܳ ૑ਗೞ૑ ঋח׮. DayNight Theme

    values/theme.xml <style name="ThemeOverlay.MaterialComponents.DayNight" parent="ThemeOverlay.MaterialComponents.Light"/> values-night/theme.xml <style name="ThemeOverlay.MaterialComponents.DayNight" parent="ThemeOverlay.MaterialComponents"/>
  41. CodeLab • res/layout/home_activity.xml S T E P 6 Use DayNight

    theme (1/1) <!--TODO: STEP6 - Use DayNight theme --> <androidx.appcompat.widget.Toolbar android:id="@+id/toolbar" ... app:popupTheme="@style/ThemeOverlay.AppCompat.DayNight" />
  42. "Developing Themes with Style" #3. Layer your themes for re-use

    Link: https://j.mp/themes-styles?slide=176
  43. CodeLab • start/build.gradle S T E P 7. O P

    T I O N A L Layer your themes (1/4) //TODO: STEP7 - Layer your themes android { compileSdkVersion 29 buildToolsVersion "29.0.0" defaultConfig { applicationId "soup.codelab.darktheme" minSdkVersion 21 targetSdkVersion 29 ...
  44. CodeLab • res/values/themes.xml S T E P 7. O P

    T I O N A L Layer your themes (2/4) <!-- TODO: STEP7 - Layer your themes --> <style name="Platform.Theme.Github" parent="Theme.AppCompat.DayNight" /> <style name="Base.Theme.Github" parent="Platform.Theme.Github" />
  45. CodeLab • res/values-v29/themes.xml S T E P 7. O P

    T I O N A L Layer your themes (3/4) <!-- TODO: STEP7 - Layer your themes --> <style name="Platform.Theme.Github" parent="Theme.AppCompat.DayNight"> <item name="android:isLightTheme">true</item> <item name="android:forceDarkAllowed">true</item> </style>
  46. CodeLab • res/values/styles.xml • res/values-night/styles.xml S T E P 7.

    O P T I O N A L Layer your themes (4/4) <!-- TODO: STEP7 - Layer your themes --> <style name="AppTheme.Github" parent="Base.Theme.Github" />
  47. CodeLab • ׮௼ప݃ীࢲ BottomSheet दੋࢿ ޙઁ • Elevationਵ۽ ੋೠ Ӓܿ੗о

    ੜ উࠁੋ׮.
 
 Black Bg + Black Shadow = Black Step 8. Optional
  48. • Higher elevation, lighter surface • ߋӝח ߈ైݺೠ ൟ࢝ overlay۽

    ઑ੺ػ׮. • Elevation (0dp ~ 24dp) • Overlay Transparency (0% ~ 16%) Elevation Surface Elevation Overlay
  49. • MDC Componentsח ইې ࣘࢿী ٮۄ Elevation Overlaysо ੸ਊػ׮.
 


    
 
 • MaterialShapeDrawable, ElevationOverlayProviderܳ ੉ਊೞݶ
 Custom Viewب Elevation Overlaysܳ ࣚऔѱ ੸ਊೡ ࣻ ੓׮. • ਗ஖ ঋח ҃਋, elevationOverlaysEnabled ࣘࢿਸ false۽ ߸҃ೞݶ ػ׮. Elevation Overlays E L E V A T I O N <style name="Theme.MaterialComponents" parent="..."> <item name="elevationOverlaysEnabled">true</item> <item name="elevationOverlaysColor">?attr/colorOnSurface</item> </style>
  50. • Elevationী ٮۄ Overlay ࢚࢝җ ߓ҃࢝ਸ ੸੺൤ ࢴযળ׮. ElevationOverlayProvider E

    L E V A T I O N MDC 1.1.0 @ColorInt // layered color, if elevationOverlaysEnabled == true public int layerOverlayIfNeeded(@ColorInt int bgColor, float elevation) @ColorInt // layered color, always public int layerOverlay(@ColorInt int bgColor, float elevation) @ColorInt // layered color, of attr/colorSurface public int getSurfaceColorWithOverlayIfNeeded(float elevation) C
  51. • MDCীࢲ ߓ҃ী ࢎਊغח Drawable۽,
 ղࠗ੸ਵ۽ ElevationOverlayProviderܳ ࢎਊೠ׮.
 
 


    
 • ز੸ਵ۽ Elevation ߸҃੉ оמೞ׮. MaterialShapeDrawable E L E V A T I O N private val bgDrawable = MaterialShapeDrawable().apply { initializeElevationOverlay(context) fillColor = context.getColorAttr(R.attr.colorSurface) } bgDrawable.setElevation(float elevation) C
  52. • MDC Guideline: WCAG’s AA ળࣻܳ ӂ੢ • ੘਷ ఫझ౟

    - ୭ࣗ 4.5:1 • ௾ ఫझ౟ - ୭ࣗ 3.0:1 • Text, BG р ؀࠺о ୭ࣗ 15.8:1 ח غযঠ
 24dp elevationীࢲ body textо AAܳ ݅઒ • 24dp = ୭؀ elevation (MDC) Accessibility E L E V A T I O N #121212 8% Primary Dark Primary #1F1B24 Link: https://www.w3.org/TR/UNDERSTANDING-WCAG20/visual-audio-contrast-contrast.html
  53. CodeLab • start/build.gradle S T E P 8. O P

    T I O N A L Get Lighter Surface (1/4) //TODO: STEP8 - Get Lighter Surface implementation 'com.google.android.material:material:1.1.0-alpha08'
  54. CodeLab • res/values/styles.xml S T E P 8. O P

    T I O N A L Get Lighter Surface (2/4) <!-- TODO: STEP8 - Get Lighter Surface --> <style name="AppTheme.BottomSheet" parent="Theme.MaterialComponents.DayNight"> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> <item name="colorSurface">@color/colorBackground</item> </style>
  55. CodeLab • MaterialViewBindingAdapter.kt S T E P 8. O P

    T I O N A L Get Lighter Surface (3/4) /* TODO: STEP8 - Get Lighter Surface */ @BindingAdapter("elevationOverlaysEnabled") fun setElevationOverlaysEnabled(view: View, enabled: Boolean) { view.background = if (enabled) { MaterialShapeDrawable.createWithElevationOverlay( view.context, view.elevation) } else { ... } }
  56. CodeLab • res/layout/home_bottom_sheet.xml S T E P 8. O P

    T I O N A L Get Lighter Surface (4/4) <!-- TODO: STEP8 - Get Lighter Surface --> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:elevation="8dp" android:theme="@style/AppTheme.BottomSheet" app:elevationOverlaysEnabled="@{true}">
  57. • Notification਷ ੗ز ੸ਊػ׮. • Custom Notification਷ ইې styleਸ ࢎਊೡ

    Ѫ • TextAppearance.Compat.Notification • ױ, ࢖ࢿ P OSח ੸ਊ ؀࢚੉ ইפ׮. Notification