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回目)
KotlinでGsonでStringをBooleanにする
やったこと
AndroidでRetrofit + Gsonを使っているときのおはなし。
APIレスポンスにStringで"0"、"1"が返ってくる場面に出くわして
これをBooleanとして扱いたくってTypeAdapter
を使ったよ。
なにが起きたか
{ "is_success": "1" }
みたいなやつをBooleanで扱うぞと思って
data class Response( @SerializedName("is_success") val isSuccess: Boolean )
というふうにしてたら全部true
になった。全てが正になった困った。
どうやったか
パッと思いついたのはコンバータクラス作って
// レスポンスはStringで受ける // data class Response( // @SerializedName("is_success") // val isSuccess: String // ) object ResponseConverter { fun convert(res: Response) = Item(isSuccess = res.isSuccess == "1") } fun Response.convert() = ResponseConverter.convert(this)
みたいにするのだけど、毎回するのアレだよな〜と思って調べたら
TypeAdapter
なるものを知った。詳しくは説明しないけど便利。
ということで
class IntToBooleanTypeAdapter : TypeAdapter<Boolean>() { override fun write(out: JsonWriter, value: Boolean?) { if (value == null) { out.nullValue() return } out.value(if (value) 1 else 0) } override fun read(`in`: JsonReader): Boolean { if (`in`.peek() == null) return false return `in`.nextInt() == 1 } }
というふうにしてあげて、レスポンスを
data class Response( @SerializedName("is_success") @JsonAdapter(IntToBooleanTypeAdapter::class) val isSuccess: Boolean )
のようにしてあげることで、無事変換された!!
おわりに
Gsonがどのようにうまいこと変換してくれるかまで
調べるのに手が回ってないので時間ができたら調べる。
Gsonなのか、Kotlinの型の問題なのかわすれちゃった。。
Javaのときはできてたような…できてなかったような…
調べたら追記するかも。明日はDroidKaigi。
使わないパラメータでWarningを出さない for Kotlin
Androidの話。
MVVMアーキテクチャで開発をしていると、ViewModelにクリックメソッドを実装する事が多い。
その際、
fun onClickHoge(view: View) { someThing() }
のように定義するんだけど、このview
というパラメータはそこまで使わない。
使わないパラメータで警告を出さないようにしようと
fun onClickHoge(@SuppressWarnings("unused") view: View) { someThing() }
としてたんだけど、これでは警告が抑えられていなかった。
調べてみると、これはJava
の書き方のようで、Kotlinだと@Suppress
を使うらしい。
そこで、
fun onClickHoge(@Suppress("unused") view: View) { someThing() }
としたんだけど、これでも警告が抑えられていなかった。
調べてみると、unused
じゃなくてUNUSED_PARAMETER
を使うらしい。
そこで、
fun onClickHoge(@Suppress("UNUSED_PARAMETER") view: View) { someThing() }
とすると、警告が抑えられた!🙌
conclusion
困ったらalt
+ Enter
だ 🙏