【Android】アプリバーの文字・メニュー・背景色変更方法まとめ

# 概要
Androidアプリの画面上部のアプリバー（AppBar, ActionBar, Toolbarとも）に、メニューアイコンや「保存」のようなメニューボタンを設置したり、アイコン・文字や背景の色を変えたいことがある。方法を調べてまとめた。

# アプリ・アクティビティ全体のスタイルを設定する
AndroidManifestの`<application>`でアプリ全体のテーマを設定できる。
`<activity>`で設定した場合はアクティビティ全体のテーマになる。

```AndroidManifest.xml
<application
    ...中略...
    android:theme="@style/AppTheme" >
    ...中略...
</application>
```

```styles.xml
<resources>
    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="actionMenuTextColor">@color/menuText</item>
    </style>
</resources>
```

```colors.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#FF0000</color>
    <color name="colorPrimaryDark">#00FF00</color>
    <color name="colorAccent">#0000FF</color>
    <color name="menuText">#00FFFF</color>
</resources>
```

- `colorPrimary`: アプリバー（やフローティングアクションボタン）などのUIで使われる基本色を設定する
![スクリーンショット 2020-02-17 12.22.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/a7885f9b-d945-a4f1-c4bb-af4236103c55.png)


- `colorPrimaryDark`: 暗い部分の基本色を設定する
![スクリーンショット 2020-02-17 12.21.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/4cf83400-9afd-1dc1-fcf5-29b8cc958a11.png)


- `colorAccent`: テキストボックスやダイアログなどのUIで使われる色を設定する
![スクリーンショット 2020-02-17 12.21.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/c0fed00b-ae3d-b268-e973-604185924b3d.png)![スクリーンショット 2020-02-17 12.17.57 のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/ef0b796e-c510-283b-21fa-d62d0a5dd934.png)



- `actionMenuTextColor`: アプリバーのメニューの文字色を設定する
![スクリーンショット 2020-02-17 12.21.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/35f91e91-b14c-7a23-c4d6-5f4beda98d41.png)


# Fragmentごとにスタイルを変更する
上記のスタイル設定では、Fragmentごとの設定はできない。
各Fragmentでアプリバーの背景色・メニューなどのスタイルを変更する方法を紹介する。

## アプリバーの背景色を変更する
`activity?.supportActionBar?.setBackgroundDrawable()`で色（`ColorDrawable`）をセットする。
一度色を変えるとFragment遷移してもそのままであるため、色を戻したい場合は、よしななタイミング（別画面に遷移する時など）で元の色をセットする必要がある。

```Fragment.kt
activity?.supportActionBar?.setBackgroundDrawable(ColorDrawable(Color.WHITE))) // アプリバーを白にする
```
![スクリーンショット 2020-02-17 12.39.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/4847257c-9ec2-7f5d-9855-353035fd2eee.png)


## アプリバーのタイトルの文字色を変更する
ベストプラクティスが分からないが、任意の色を付けた`SpannableString`をセットするのが良さそうだろうか。
### HTMLでゴリ押す
HTMLタグで文字に色を付けてセットする。

```Fragment.kt
val titleHtml = "<font color=\"#FF0000\">HTMLタイトル</font>"
activity?.supportActionBar?.apply {
    setTitle(Html.fromHtml(titleHtml))
    setBackgroundDrawable(ColorDrawable(Color.WHITE))
}
```
![スクリーンショット 2020-02-17 12.44.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/803aa6e2-dc91-e681-70b7-fa3183f06cea.png)


### SpannableStringで色を付ける
[`ForegroundColorSpan`](https://developer.android.com/reference/kotlin/android/text/style/ForegroundColorSpan.html)というSpanで文字に色を付けてセットする。

```kotlin
val title = SpannableString("SpannableStringタイトル")
title.setSpan(ForegroundColorSpan(Color.RED), 0, title.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
activity?.supportActionBar?.apply {
    setTitle(title)
    setBackgroundDrawable(ColorDrawable(Color.WHITE))
}
```
![スクリーンショット 2020-02-17 12.46.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/860379f5-fefe-0206-e255-3afb2b1cb084.png)


## アプリバーにメニューを表示する
`onCreateOptionsMenu()`内で任意のメニューをセットし、アプリバーにメニューアイコンや文字（「保存」「閉じる」など）を表示する。

```Fragment.kt
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        super.onCreateView(inflater, container, savedInstanceState)
        this.setHasOptionsMenu(true)
    }

    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.hoge_menu, menu)
    }
```

```hoge_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/action_hoge_icon"
        android:icon="@drawable/hoge_icon"
        app:showAsAction="always" />
    <item
        android:id="@+id/action_hoge_text"
        android:title="hoge"
        app:showAsAction="always" />
</menu>
```
<img width="29" alt="hoge_icon.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/24b74771-4773-6d9b-45f1-b19af3716d1e.png">←hoge_icon.png
![スクリーンショット 2020-02-17 13.26.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/5fab321e-e141-46c4-1f06-8d2fdd807770.png)



## アプリバーのメニューの文字色を変更する
`onCreateOptionsMenu()`内で該当のメニューアイテムを取得し、`ForegroundColorSpan()`をセットする。
`SpannableString`作成の際に文字列を変更することもできる。

```Fragment.kt
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.hoge_menu, menu)
        val item = menu.findItem(R.id.action_hoge_text) // メニューアイテム取得
        val s = SpannableString("fuga")
        s.setSpan(ForegroundColorSpan(Color.YELLOW), 0, s.length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE)
        item.setTitle(s) // メニューアイテムにSpannableをセット
    }
```
![スクリーンショット 2020-02-17 13.33.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/67ccc204-245f-a019-fbec-596e0bf20652.png)


## アプリバーのメニューアイコンの色を変更する
`onCreateOptionsMenu()`内で該当のメニューアイテムの`icon`（`Drawable`）を取得し、`setColorFilter()`で色を変更する。
フィルターの種類については[`PorterDuff.Mode`](https://developer.android.com/reference/kotlin/android/graphics/PorterDuff.Mode.html)を参照されたい。

```Fragment.kt
    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.hoge_menu, menu)
        val item = menu.findItem(R.id.action_hoge_icon)
        item.icon?.apply {
            mutate() // Drawableを変更可能にする
            setColorFilter(Color.WHITE, PorterDuff.Mode.SRC_ATOP) // アイコンを白くする
        }
    }
```
![スクリーンショット 2020-02-17 13.41.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124752/6c92ccf3-a12c-a58d-4561-4c3be593cc94.png)


# まとめ
アプリバーの文字色・メニューアイテムの色・背景色変更について、アプリ全体・個別Fragmentでの方法を紹介した。