16
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

and factoryAdvent Calendar 2020

Day 11

【Android】ちょっと便利なDrawableを書く

Last updated at Posted at 2020-12-11

この記事はand factory Advent Calendar 2020の11日目の記事です。
昨日は@tokiyanさんの [BigSur] アプリケーションを開くためのアクセス権限がありません。の対処法 でした。

はじめに

Viewを角丸にする・色を変えるなど、Drawableを書く機会は多いと思います。
この記事では、私が個人的によく使っているDrawableの書き方のサンプルを紹介したいと思います。

色と同時にEffectを指定する

backgroundにcolorを指定し、foregroundにRippleEffectを指定する、なんて書き方をしている人は多いのでは無いでしょうか。
もちろんそれでも可能ですが、Effectを付け忘れること心配や、foreground指定がAPIレベルが23以上でないと使えないといった問題もあります。
そんな時に、Backgroundの色とEffectを同時に指定したDrawableを用意してしまうと便利です。

bg_color_effect.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:attr/colorControlHighlight">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/blue" />
        </shape>
    </item>
</ripple>

view1.gif

shapeのみで使うパターンにrippleを被せただけです。
これをbackgroundに指定すれば、背景色 @color/blue と、RiipleEffectが同時に適応できます。
なお、 ?android:attr/colorControlHighlight はデフォルトのRiipleEffectのカラーです。

角丸などの変形View+Effect

角丸のViewなどをDrawableで作っても、Effectがそれをはみ出してしまう例をよく見ると思います。
あれはRipleEffectがView全体に広がってしまうのが原因です。
これも先程と同じ様にrippleを被せると、Effectがその範囲だけに広がってくれます。

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:attr/colorControlHighlight">
    <item>
        <shape android:shape="rectangle">
            <corners android:radius="@dimen/button_radius" /> <!-- 角の丸み -->
            <solid android:color="@color/blue" />
        </shape>
    </item>
</ripple>

view2.gif
Effectが角をはみ出ません

Effect Only

ベタ塗りや枠の描画は行わず、Effectだけを適応するDrawableを作ることもできます。
複雑なViewの上部にFrameLayoutをかぶせて、そこにEffectを適用したい場合に使えます。

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:attr/colorControlHighlight">
    <item android:id="@android:id/mask"> <!-- maskを指定する -->
        <shape android:shape="rectangle">
            <solid android:color="@color/white" />
        </shape>
    </item>
</ripple>

id/mask以下の要素でEffectがMaskされます。
これは塗りつぶしているので、EffectだけのDrawableになります。

view3.gif

円形Effect Only

先程のを応用すると、円形のEffectだけのDrawableなんかもできます。
円形のViewをはみ出すようなEffectを付けたい場合などに使えると思います。

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="?android:attr/colorControlHighlight">
    <item android:id="@android:id/mask">
        <shape android:shape="oval"> <!-- ovalを指定 -->
            <solid android:color="@color/white" />
        </shape>
    </item>
</ripple>

view4.gif
Viewに沿ったovalになるので、長方形、正方形のViewでそれぞれ形が変わります。

Effectを動的に作る

動的にViewを作りつつ、背景色を変え、Effectも付ける、なんていう時にはDrawableを動的に書く必要がでてきます。
#ffffff などを引数にして、以下の様に作る事ができます。

fun TextView.setCustomDrawable(textColor: String, backgroundColor: String, borderColor: String) {
    if (textColor.isNotBlank() && backgroundColor.isNotBlank() && borderColor.isNotBlank()) {
        setTextColor(Color.parseColor(textColor))
        // 角丸と色の設定
        val pressedDrawable = GradientDrawable().apply {
            setColor(Color.parseColor(backgroundColor))
            cornerRadius = context.resources.getDimensionPixelSize(R.dimen.radius).toFloat() // radiusは定義しているとします
            setStroke(4, Color.parseColor(borderColor)) // `1`はStorkeのWidth
        }
        // `?android:attr/colorControlHighlight` の取得
        val typedValue = TypedValue()
        context.theme.resolveAttribute(android.R.attr.colorControlHighlight, typedValue, true)
        val color = ContextCompat.getColor(context, typedValue.resourceId)
        // RippleEffectの設定
        val rippleDrawable = RippleDrawable(ColorStateList.valueOf(color), pressedDrawable, pressedDrawable)
        this.background = rippleDrawable
    }
}

view5.gif
少し複雑ですが、これで目的は果たせると思います。

placeholderを自作する

少し毛色を変え、placeholderに使えるDrawableについてです。
対象として、アプリのロゴを入れたplaceholderを使う場合を想定しています。
placeholderを設定する箇所毎に、サイズの違う画像をデザイナーが用意してそれを使用する、なんていう事があると思います。
そんな時は、placeholder用のアプリロゴだけ用意してもらい、Drawableで必要サイズの画像を用意してしまえば、
画像分の容量が削減でき、デザイナーの負担も減ると思います。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@android:color/darker_gray" /> <!-- 背景色を指定 -->
            <size
                android:width="100dp"
                android:height="100dp" />
        </shape>
    </item>
    <item
        android:width="24dp"
        android:height="24dp"
        android:drawable="@drawable/icon_logo"
        android:gravity="center" />
</layer-list>

また、これで作成した画像は scaleType="fitXY" で配置すると、伸縮するのが背景色部分になり、ロゴのサイズ自体は変わりません。
これで更に細かく画像を用意する必要が減ると思います。

おわりに

Drawableをうまく活用すると、結構いろいろなViewが作れます。
是非Drawableを活用し、UIのブラッシュアップや、容量・手間の削減に役立ててください。

16
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?