AndroidのSkeletonプロジェクト作ってみてる
個人プロジェクトだったり検証用サンプルだったり、作り始めるときに毎回書いているコードないですか。
Timberの初期化だったりモノによってはDaggerだったり。
そんなときにクローンしてパッケージ変えて使えるの作ってみてます🙋🏻♂️
github.com
気が向いたときに少しずつ整えていきたいし、自分用にメンテもしていきたい。
実プロダクト向けではないのでどんどんalpha版/beta版つっこんでいくぞ!
蛇足
スケルトン作るぞって思ってちょこちょこ作業してたけど、なぜかTODOぽいものを作ろうとしてしまう自分がいて、それはTodoサンプルや…と自分と戦いながら最終的には不要なコードが散見される感じになってしまったw
とはいえアーキテクチャ的に参考になる部分は含めたいのでまたちょこちょこアップデートしたい。なにがいるかな?
コードの間違いやアドバイスは大歓迎なのでスターください!(?)
Toolbarを使うときのtheme設定
Toolbarにメニューを表示するとよく引っかかるのがアイコンの色の定義。
特に、独自で設定したメニューアイコンと、オーバーフローメニューのアイコンの色がうまく合わないというパターン。
今回はここを解決するひとつの方法をメモ。
前提
- MDC Library ver1.2.0-alpha05
実装
Toolbar用のThemeOverlayに以下の2つが用意されていた
ThemeOverlay.MaterialComponents.Toolbar.PrimaryThemeOverlay.MaterialComponents.Toolbar.Surface
<style name="ThemeOverlay.MaterialComponents.Toolbar.Primary" parent=""> <item name="colorControlNormal">?attr/colorOnPrimary</item> <item name="actionMenuTextColor">?attr/colorOnPrimary</item> </style> <style name="ThemeOverlay.MaterialComponents.Toolbar.Surface" parent=""> <item name="colorControlNormal">@color/material_on_surface_emphasis_medium</item> <item name="actionMenuTextColor">@color/material_on_surface_emphasis_medium</item> </style>
@color/material_on_surface_emphasis_mediumは、colorOnSurfaceの60%透過色です。
これをToolbarのテーマに適用させると楽そう。(Toolbar単体で使うとき)
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:theme="@style/ThemeOverlay.MaterialComponents.Toolbar.Primary" />
あるいは、各プロジェクトのテーマに応じて独自のThemeOverlayを作るのも良さそう
<!-- アイコンカラーをPrimarySurfaceに --> <style name="ThemeOverlay.AppName.Toolbar.PrimarySurface" parent=""> <item name="colorControlNormal">?attr/colorOnPrimarySurface</item> <item name="actionMenuTextColor">?attr/colorOnPrimarySurface</item> </style>
さらに、ToolbarのアイコンカラーはcolorControlNormalで決まるので、
アイコン側にも?attr/colorControlNormalのtintをかけるといい感じになりそう。
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M17.6,11.48 ..." />
</vector>
他のやり方
いい感じにしたくてthemeを漁ったりしてみてやったぜって言ってたけど、menuのアイコンカラーを変えるだけならapp:iconTintを使ってmenuファイル側でできるのであった…
<menu
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<item
android:id="@+id/menu_id"
android:icon="@drawable/ic_android"
android:title="@string/menu_label"
app:iconTint="?attr/colorOnPrimarySurface"
app:showAsAction="always"
/>
</menu>
Buttonにスタイルを設定する
そりゃそうだよねって感じではあるんだけど、あれこれどうするっけ…
ってよく調べなおすので自分で書いて覚えよう選手権を開催します。
よくあるシーン
ボタンに背景色つけるぞ!ボタンの文字色も変えるぞ!
ちゃんとenabledを設定して制御するぞ!
困った!enabled=falseなのに背景色も文字色も変わらん!OMG!
解決策
ColorStateListでボタンの状態に応じた色を背景色・文字色に設定しよう!
せっかくだし、スタイルで定義しちゃおう!
ColorStateList
たとえば、 enabled=falseのときの色は別で!なときは
res/color/background_primary.xmlのようなファイルを作って
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/darker_gray" android:state_enabled="false"/>
<item android:color="@color/colorPrimary"/>
</selector>
としてあげるだけ。便利!
スタイルに設定してあげる
これを文字色も同じように作ってあげて、
<!-- Buttonのスタイル -->
<style name="Material.RadiusButton" parent="Widget.MaterialComponents.Button.UnelevatedButton">
<item name="backgroundTint">@color/background_primary</item>
<item name="rippleColor">@color/colorAccent</item>
<item name="android:layout_height">@dimen/button_height_base</item>
<item name="cornerRadius">@dimen/button_radius_base</item>
<item name="android:textColor">@color/button_text</item>
</style>
ボタンにスタイルを適用する
<android.support.design.button.MaterialButton
android:id="@+id/button"
style="@style/Material.RadiusButton"
android:layout_width="match_parent"
android:enabled="@{!viewModel.executing}"
android:onClick="@{() -> viewModel.onClick()}"
android:text="@string/button_text"/>
とすれば、管理が楽ですね!めっちゃ説明を端折りました!
まとめ
書いたらきっと思い出せる!便利!
ioschedのToolbar周りを見てみた
iosched 2018が公開されましたね!知見たっぷり🎉
Tooblar`周りをどうしようか悩んでいたので抜粋。
BottomNavigationViewを使ったときのあれ。
ioschedではActivityでToolbarを持つ形ではないようでした。個人的に先入観もありビックリ。
結論から言うと、FragmentでAppBarLayoutを持たせる感じでした。
スケジュールタブの場合は
<AppBarLayout>
<FrameLayout app:layout_scrollFlags="scroll|snap|exitUntilCollapsed">
<ImageView android:layout_gravity="center_vertical|start"/>
<TextView android:textAppearance="@style/TextAppearance.IOSched.ToolbarTitle"/>
</FrameLayout>
<TabLayout/>
</AppBarLayout>
といった具合です。ガッツリImageViewもTextViewも位置指定してました。
ちょっと気になってToolbarのUseageを探してみたところ、ファイルとしてはtoolbar.xmlはあるものの
これどこも使ってないように見受けられます(違ったら教えてほしい!)
UpNavigationが気になる。
ここで気になるのがスケジュール等の詳細のUpNavigation周りになってきます。
Toolbarではなく普通にImageViewでした。わお。
<ImageButton
android:id="@+id/up"
android:layout_width="?actionBarSize"
android:layout_height="?actionBarSize"
android:layout_gravity="start|top"
android:background="?selectableItemBackgroundBorderless"
android:contentDescription="@string/navigate_up"
app:srcCompat="@drawable/ic_arrow_back" />
こんな具合です。知らなかった。。
スクロールに応じて見えなくなったりもしていたのでてっきりToolbarかと思ってました。
この挙動についてはPushUpScrollListenerで定義されているようです。
感想
Material studiesを見ていると、Toolbar周りの自由度がグッと上がった気がしていて
勝手にToolbarを拡張と考えていましたが、結構筋肉で実装していく感じになるのかな?
KotlinのSealedクラス使いたくて無理をした
Kotlinのsealed classを使いたいと虎視眈々だったんだけど
ついに突っ込んでみた。今回の用途ではそんなにメリットはないけど。
よくある成功or失敗を柔軟にという感じはなくemunの拡張くらいの気持ち。
使ったとこ
Firebase AnalyticsでUser Propertyを設定したかったんだけど、enumで
enum class UserProperty(
val propertyName: String,
val value: String
) {
AREA_KYUSYU("area", "九州),
AREA_SHIKOKU("area", "四国),
...
}
とするのは毎回areaって書かなきゃなのがかっこ悪いなと。
おっ、と思ってsealed class使って見ると
sealed class UserProperty(
val name: String,
open val value: String
) {
abstract class Area(override val value: String) : UserProperty("area", value)
object Kyushu : Area("male")
object Shikoku : Area("female")
...
}
って書けた。コレジャナイ感は否めないけど、こっちのほうが好みなので良しとしよう。
まとめ
もっと活用していこう。あとブログちゃんと書くぞ!(n回目)