見出し画像

【エンジニアBlog】 アーティスト支援プラットフォーム「ArtSticker」のAndroid版がダークモードに対応しました!

こんにちは。Androidエンジニアの@akihito-okadaです。アーティスト支援プラットフォーム「ArtSticker」のAndroid版の開発を行なっています。

現在、かなりの少数精鋭で開発を行なっている「ArtSticker」。それぞれの工数がなかなか大きく割けない中で、デザイナー陣やプロデューサー陣など、他メンバーとどのように連携しながら開発をしているか、実際にどのような仕組みでプロダクトが動いているのか皆さんにもお伝えできれば「ArtSticker」をより楽しんでいただけるのでは、と思い、今後は開発ブログも公開していきたいと思います。

The Chain Museumのnoteでは、アプリでお楽しみいただけるアートイベント情報やインタビューを中心にお伝えしてきましたが、こちらも併せてお楽しみいただけると嬉しいです!

● はじめに

アーティスト支援プラットフォーム「ArtSticker」のAndroid版がダークモードに対応しました!
これまで「ArtSticker」は白をベースとした明るいデザインでしたが、黒をベースとしたダークモードに変更できるようになりました!

画像3

初期設定は、今までのデザインのままですが、設定画面からダークモードを選択できるようになっています。

変更手順は、「マイページ」→右上の設定を選択→「アプリのテーマを変更」→「ダークテーマ」を選択。となります。

ダークモード.001


・なぜ、ダークモードを採用したか?

iOS 13やAndroid 10で、OSの設定にダークモードが追加され、OSの設定に従いダークモードを切り替える実装が多くのアプリで採用されつつあります。
一般的に、ダークモードは省電力であったり視認性が向上するなどの効果があると言われていますが、
ArtStickerにおいては、背景が暗くなることで掲載している作品の画像がよりきれいに見える効果があると感じています。

画像5

ただ開発組織のアプリ開発において、ダークモードを実装する上では、以下のような問題があり、導入を見送るケースも多いのではないかと思います。

1. 解決するべき課題が他にあり、十分な時間を確保できない
2. 既存のテーマに加え、ダークモードの管理が必要になるため、デザイン管理の負担が増える
3. テストパターンが増え負担になる

今回は、リソースの少ないチームの中で、上記問題を解決しながら対応を行いました。
リリースまでの進め方や、Androidの技術的な事などを共有したいと思います。


● チームの開発状況

まずAndroid開発に関わる現在のチーム状況です。

Androidエンジニア: 1名
デザイナー: 1名

リソースは少ないけど、やりたいことはたくさんあるので、ダークモードの優先度は低い。
でも、勉強を兼ねてダークモードに対応したいという状況でした。
ということで、デザイナーさんのできる限り負担をかけずに、ダークモードに対応しようと考えました。

・工数を減らすために

デザインの管理は基本的にSketchで行っており、通常の機能開発では、デザイナーさんにSketch上でデザインを作ってもらってから開発を進めていますが、今回はできる限りその作業を削りました。


● リリースまでの流れ

以下のような流れで進めました。

Step 1. 最低限必要な実装をしてゴールまでの距離を確認
Step 2. デザイナーさんとDark Themeの勉強会を開く
Step 3. Step 2ですり合わせたイメージを元に実装をすすめる
Step 4. デザインチェック
Step 5. リリース


● Step 1. 最低限必要な実装をして、ゴールまでの距離を確認

まずは、ダークモードの対応の全体感を掴むために、シンプルな設定を入れます。

・NotNight/Night Modeを切り替えられる DayNight のThemeをActivityに設定

<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">

・Debugビルドのときのみ、OSのTheme設定に従うようにApplicationクラスで設定

override fun onCreate() {
   super.onCreate()
   AppCompatDelegate.setDefaultNightMode(
       if (BuildConfig.DEBUG) {
           AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
       } else AppCompatDelegate.MODE_NIGHT_NO
   )
}

・night用の最低限のリソースファイルを作り、最低限の設定を追加

<color name="colorPrimary">@color/white</color>
<color name="colorPrimaryDark">@color/black</color>
<color name="colorAccent">@color/black</color>
<color name="colorPrimary">@color/black</color>
<color name="colorPrimaryDark">@color/white</color>
<color name="colorAccent">@color/gray_cccccc</color>

・動作確認をする
Android 10の端末やエミュレーターで、ダークモードの設定を変え、動作を確認します

● Step 2. デザイナーさんとDark Themeの勉強会を開く

Material DesignのDark Themeの読み合わせをする
・今回は日本語に翻訳をかけて、段落毎に順番に読み、議論しながらすすめました
Material DesignのDark Themeのレイヤーの考え方を理解する
・Light ThemeとDark Themeでelevationの考え方を統一します
・ベースカラーを決め、その上に白に以下の透明度をレイヤーを重ね、各dp毎の色を作成します
・Material DesignのDefault Elevationから各コンポーネントの色を決定します

画像4

・開発中のアプリだったらという前提でレイヤーや使用する色の意識合わせをする
自然とそういう流れになると思いますが議論します。

・どのアプリのダークモードに近いものを目指すか議論する

ダークモードに対応したアプリが増えてきているので、ゴールを共有します。

・ダークモードが増えた場合の運用負荷について議論する
デザインの管理を今後どうするか共有します。

● Step 3. すり合わせたイメージを元に実装をする

・最低限の色の定義を行う
    ・ベースカラーと各レイヤー毎の色を仮置で定義します

<color name="black_00dp">#0f0f0f</color>
<color name="black_01dp">#1a1a1a</color>
<color name="black_02dp">#1c1c1c</color>
<color name="black_03dp">#1e1e1e</color>
<color name="black_04dp">#202020</color>
<color name="black_05dp">#222222</color>
<color name="black_06dp">#242424</color>
<color name="black_08dp">#282828</color>
<color name="black_12dp">#2f2f2f</color>
<color name="black_16dp">#383838</color>
<color name="black_24dp">#484848</color>

・テキストカラーをLightなアプリのルールに従って定義します

<color name="textColor">@color/white</color>
<color name="textColorPrimary">@color/white</color>
<color name="textColorSecondary">@color/gray</color>

・各コンポーネントの色を定義します

<color name="colorBorder">@color/black_01dp</color>
<color name="colorSurface">@color/black_02dp</color>
<color name="colorCardLayout">@color/black_03dp</color>
<color name="colorAppBarLayout">@color/black_04dp</color>
<color name="colorTabLayout">@color/black_04dp</color>
<color name="colorBottomNavigationView">@color/black_08dp</color>
<color name="colorDialog">@color/black_24dp</color>


・Viewに設定していく

・使用する色の方針が決まったら、Viewに設定します
・共通のコンポーネント毎に、styleにまとめながら実装すると、きれいに書くことができます
・既存のLightモードの実装がいまいちな場合はリファクタリングしながら設定します

<style name="App.Widget.AppBarLayout" parent="Widget.Design.AppBarLayout" >
   <item name="android:layout_width">match_parent</item>
   <item name="android:layout_height">wrap_content</item>
   <item name="android:background">@color/colorAppBarLayout</item>
</style>
<com.google.android.material.appbar.AppBarLayout
   android:id="@+id/app_bar"
   style="@style/App.Widget.AppBarLayout">


・Vector Drawableの対応方法

・Context Menuに設定したVector Drawableは以下のように "android:tint="?attr/colorControlNormal" を vector tagに設定するとNightModeの設定に従って色が変更されます
・この時、設定したThemeの "android:textColorSecondary " に従って色が決定します

<vector xmlns:android="http://schemas.android.com/apk/res/android"
   android:width="11dp"
   android:height="10dp"
   android:viewportWidth="11"
   android:viewportHeight="10"
   android:tint="?attr/colorControlNormal">
   <!--  省略 -->
</vector>

・pngやwebp画像の対応方法

・自動で設定することはできないため、 drawable-night 配下に同じファイル名でリソースを置きます

・設定画面に、切り替えメニューを作る

今回は設定画面にメニューを追加し、Dialogを表示してモードを切り替えられるようにしました

・変更後の実装

class SettingsFragment : Fragment(), NightModeDelegate {
   fun showChangeNightModeDialog() {
       ChangeNightModeDialogFragment.instance(nightMode).also {
           it.onClickNightMode = { selectedNightMode ->
               val shouldUpdateState = nightMode != selectedNightMode
               if (shouldUpdateState) {
                   // SharedPreferencesに設定を保存
                   actionCreator.selectNightMode(selectedNightMode)
                   // Themeを変更
                   updateNightMode(selectedNightMode)
                   // Activityを再生成
                   navigator.navigateToMainWithClearTop(activity)
               }
           }
           it.show(childFragmentManager, ChangeNightModeDialogFragment::class.java.simpleName)
       }
   }

・変更処理詳細

interface NightModeDelegate {
   fun updateNightMode(nightMode: NightModeType) {
       AppCompatDelegate.setDefaultNightMode(
           when (nightMode) {
               NightModeType.NotNight -> AppCompatDelegate.MODE_NIGHT_NO
               NightModeType.Night -> AppCompatDelegate.MODE_NIGHT_YES
               NightModeType.FollowDeviceTheme -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
           }
       )
   }
}

・アプリ起動時の設定

class ArtStickerApplication : Application, NightModeDelegate {
 override fun onCreate() {
     super.onCreate()
     updateNightMode(currentNightMode)
 }
}

今回は、Night Modeをオフ(NotNight)の状態を初期値としました。

・オーバードローのチェック

・オーバードローが少なくなるように実装します
・ダークモードに限った話ではないですが、開発者向けオプションの「GPUオーバードローをデバッグ」をONにして、無駄なオーバードローが発生していないか確認します

・デザイナーさんに共有する

・数画面作り、デザイナーさんに共有し、調整します
・ダークモードにした時に別のリソースにする必要のある画像を洗い出し、必要に応じて作成を依頼します
・概ね良さそうであれば最後まで実装します

● Step 4. デザインチェック

・最後に、デザイナーさんに一通りチェックしてもらいます
    ・Step 3で作成した色の設定を共有し調整してもらいます
 ・色の設定が変わってもViewのレイヤー構造が変わらなければ、大きな変更はせずに済みます
 ・画面毎に、フィードバックをもらいます
 ・修正したら、再度確認してもらい精度を上げていきます


● Step 5. リリース

・各AndroidのVersionでテストをして、リリースします

● さいごに

・少ないリソースのなかで、Android版のダークモードに対応することができました

・デザインの管理をコンポーネント毎の色の管理に留めることで、デザイナーさんの負荷を下げることができました

・Material Designに従い、共通のコンポーネントの色を統一し、共通のView毎にstyleを定義することで、開発の時間や、テストの負荷を下げることができました

・実績として、Step 1 〜 Step 4までで、片手間で作業をして2週間程度で完了しました(アプリやチームによって、作業量が変わるため、あまり参考にならないかもしれません)

・すすめ方によっては、チームのメンバーに迷惑をかけることもあると思うので、コミュニケーションは十分にとることが大事だと感じました

・社内のメンバーにダークモードをプレビューしたところ、反応がよく実装してよかったと感じています

・参考までに、ArtStickerを是非使ってみてください(現在はAndroid版のみダークモードに対応しています)


TCMは「世の中の体温をあげる」という想いをかかげ、「Soup Stock Tokyo」等を手がけてきた遠山が構想する「新たなアート体験」に、PARTYが得意とする「デジタルでの体験設計」を融合させ、アートと個人の関係をテクノロジーで変革させ、新たな価値の提示を目指しています。