---
# System prepended metadata

title: Drawable Resources
tags: [Android]

---

###### tags: `Android`
# Drawable Resources

https://blog.csdn.net/lmj623565791/article/details/43752383

https://www.jianshu.com/p/4cd87e3c43d6

https://developer.android.com/guide/topics/resources/drawable-resource#top_of_page

## StateListDrawable
我們常希望按鈕默認、按下、放開等動作的顏色不同，所以需要監聽狀態並設置 Drawable
最土法煉鋼的方式就是用程式設定各種監聽，不斷切換 Drawable
但使用 StateListDrawable 能簡化這個過程，它可針對元件的狀態制定不同的 Drawable

### 回饋感按鈕
它有很多的狀態可以選擇，以下使用常見的狀態與 TextView 做一個有回饋感的按鈕
![](https://i.imgur.com/l04UiD4.gif)

首先建立兩種背景，默認與顏色變化的 Drawable
==btn_transparent==
```xml=
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <padding
            android:left="12dp"
            android:top="4dp"
            android:right="12dp"
            android:bottom="4dp" />
    <stroke
            android:width="1dp"
            android:color="#F3F3F3" />
    <corners android:radius="10dp" />
</shape>
```

==bg_level_easy==
```xml=
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <padding
            android:left="12dp"
            android:top="4dp"
            android:right="12dp"
            android:bottom="4dp" />
    <stroke
            android:width="1dp"
            android:color="@color/gray_light" />
    <corners android:radius="10dp" />
    <solid android:color="@color/level_easy"/>
</shape>
```

再來建立一個 StateListDrawable 並輸入程式碼
==btn_level_easy==
```xml=
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:state_focused="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:state_pressed="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:drawable="@drawable/btn_transparent2"/>
</selector>
```

最後再將做好的 StateListDrawable 放到 TextView 就完成囉！
```xml=
<TextView
        android:id="@+id/tv_easy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginStart="16dp"
        android:text="@string/level_easy"
        android:textSize="@dimen/text_large"
        android:textStyle="bold"
        android:background="@drawable/btn_level_easy" />
```

### 常駐狀態按鈕
如果希望按鈕按下後放開，顏色會變化該怎麼做呢？可以使用 activated 這個狀態
這個狀態代表按鈕被激活，而如何控制激活狀態可以使用程式碼控制
![](https://i.imgur.com/vwndO6W.gif)

將上述的範例作修改，把 state_activated 加入 StateListDrawable
==btn_level_easy==
```xml=
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:state_focused="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:state_pressed="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:state_activated="true" android:drawable="@drawable/bg_level_easy"/>
    <item android:drawable="@drawable/btn_transparent2"/>
</selector>
```

然後，因為按下後會變色，所以文字的顏色也要改變，這個部分需要再製作一個 Drawable
先在 res 建立 color 資料夾，再輸入程式碼
![](https://hackmd.io/_uploads/ryHFItR43.png)

==level_text==
```xml=
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:color="@android:color/white"/>
    <item android:state_focused="true" android:color="@android:color/white" />
    <item android:state_pressed="true" android:color="@android:color/white" />
    <item android:state_activated="true" android:color="@android:color/white"/>
    <item android:color="#A5A5A5" />
</selector>
```

將文字變色套用在 TextView 的 textColor 屬性
```xml=
<TextView
        android:id="@+id/tv_easy"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:layout_marginStart="16dp"
        android:text="@string/level_easy"
        android:textSize="@dimen/text_large"
        android:textStyle="bold"
        android:background="@drawable/btn_level_easy"
        android:textColor="@color/level_text"/>
```

最後設定監聽事件改變激活狀態就完成囉！
```kotlin=
tv_easy.setOnClickListener {
    it.isActivated = !it.isActivated
}
```

:::danger
使用時要注意 StateListDrawable 會由上而下尋找符合的狀態，只要符合就返回
這也是為什麼默認狀態始終要放在最下面的原因
:::

## 用檔名取得 Drawable
```kotlin=
private fun getLevelImage(level: Int): Int {
    val name = String.format("level%d", level)
    return resources.getIdentifier(name, "drawable", context?.packageName)
}
```

## 程式碼修改 Drawable 顏色
利用 ColorFilter 可以做到顏色更換，在 ImageView、Drawable 類別下都有其函式
這樣就不用為了每個顏色去建立很多的 Drawable
```kotlin=
val bg = context.getColor(R.color.bg)

if (Build.VERSION.SDK_INT >= 29)
    view.background.colorFilter = BlendModeColorFilter(bg, BlendMode.SRC_ATOP)
else
    view.background.setColorFilter(bg, PorterDuff.Mode.SRC_ATOP)
```
[Set android shape color programmatically](https://stackoverflow.com/questions/17823451/set-android-shape-color-programmatically)
[搞明白PorterDuff.Mode](https://www.jianshu.com/p/d11892bbe055)

## 參考文章
[使用 Selector 改變 TextView 字體颜色](https://www.cnblogs.com/yuqf/p/5887970.html)
[設定只有頂部有圓角](https://stackoverflow.com/questions/8930555/android-drawable-with-rounded-corners-at-the-top-only)
