AndroidのView共通化方法まとめ

Androidで再利用可能なViewを作る方法はいくつかあります。
知識の整理のために、ケース別にまとめてみました。

# 色や余白幅を共通化したい
dimens.xml、colors.xmlで定義した値を使うことで、アプリ全体で統一感を持ったViewを作ることができます。

```xml
<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/spacing_xsmall"
    android:textColor="@color/grey600"
    android:textSize="@dimen/text_small" />
```

うまくdimens.xml、colors.xmlにまとめておけば、デザインの変更もやりやすくなります。
自分はcolors.xmlをこのようにまとめています。
⇒ [colors.xmlマイベストプラクティス](http://qiita.com/konifar/items/68f196dc7acacfcf40cf)

# stateを共通化したい
タップした時（state_pressed）、タップできない時（state_enabled）など、stateごとに状態が違うViewを作る場合は、drawable xmlが使えます。

```xml
<View
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/bg_feedback" />
```

```drawable/bg_feedback.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- タップした時は透過グレーの色 -->
    <item android:state_enabled="true" android:state_pressed="true">
        <shape android:shape="rectangle">
            <solid android:color="#0a000000" />
        </shape>
    </item>
</selector>
```

![2015-03-10_16_04_23_png.png](https://qiita-image-store.s3.amazonaws.com/0/15267/cb7d0939-9856-c8e5-57e9-81b2a600f6b8.png "2015-03-10_16_04_23_png.png")


drawableで使えるstateはこちらにまとまっています。
⇒ [StateListDrawable](http://developer.android.com/reference/android/graphics/drawable/StateListDrawable.html)
また、CustomViewを作る場合は独自stateを作ることもできます。
⇒ [Android: how to add a custom button state](http://stackoverflow.com/questions/4336060/android-how-to-add-a-custom-button-state)

# パーツごとにattributeを共通化したい
タイトルのTextView、サブタイトルのTextViewなど、xmlのattributeを共通化したい場合は、styles.xmlにまとめられます。

```styles.xml
<style name="TextTitle">
    <item name="fontPath">@string/font_medium</item>
    <item name="android:textSize">@dimen/text_large</item>
    <item name="android:textColor">@color/black</item>
</style>

<!-- nameの後に.でつなげることで、他のstyleを継承することもできます -->
<style name="TextTitle.Short">
    <item name="android:textSize">@dimen/text_medium</item>
    <item name="android:lines">1</item>
    <item name="android:ellipsize">end</item>
</style>

<style name="TextSub">
    <item name="android:textSize">@dimen/text_medium</item>
    <item name="android:textColor">@color/grey600</item>
    <item name="android:gravity">center_vertical</item>
</style>
```
![2015-03-10_16_04_23_png.png](https://qiita-image-store.s3.amazonaws.com/0/15267/bc242677-9b14-0105-5e7c-62ebe291b6c2.png "2015-03-10_16_04_23_png.png")


[[翻訳] android best practice](http://qiita.com/kgmyshin/items/a2358d54ffb3c5435d11#style%E3%82%92%E4%BD%BF%E3%81%8A%E3%81%86)でも触れられているとおり、stylesは複数のxmlに分けて管理した方がいいかもしれません。

> 大きなStyle Fileを避け、複数に分けよう

> １つのstyles.xmlだけを持つ事は止めた方が良い。styleファイルはstyle_home.xml、style_item_details.xml、styles_forms.xmlと言ったように複数持つ事ができる。res/valuesの中のファイル名は任意である。

# Viewを丸ごと使い回したい
例えば下図のように、ルートのレイアウトは違うけど一部同じレイアウトを使いたいときには`<include/>`が使えます。
![2015-03-10_16_28_51_png.png](https://qiita-image-store.s3.amazonaws.com/0/15267/16062d08-f812-7c2c-347f-3d6f4b972a6e.png "2015-03-10_16_28_51_png.png")

```item_actors.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="@dimen/spacing">
    
    <!-- 略 -->

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/txt_characters_count"
        android:layout_marginTop="@dimen/spacing_xsmall"
        android:layout_toRightOf="@id/img_thumb">

        <include layout="@layout/part_small_characters" />
    </FrameLayout>

</RelativeLayout>
```

詳しくは[Re-using Layouts with include tag](http://developer.android.com/training/improving-layouts/reusing-layouts.html)が参考になります。
`<include />`を使うとViewのネストが1つ多くなってしまうので、`<merge/>`の使い方を覚えておくとよいです。
⇒ [What is the purpose of Android's <merge> tag in XML layouts?](http://stackoverflow.com/questions/8834898/what-is-the-purpose-of-androids-merge-tag-in-xml-layouts)

ちなみに自分は、`<include>`だけで使うViewは`part_~`という名前で統一するようにしています。


#Viewのロジックも丸ごと使い回したい
Viewにデータをバインドしたり、Visibilityを切り替えたりするロジックも丸ごと使い回したい場合は、CustomViewにするとよいです。
例えば下図のような場合。

![2015-03-10_17_00_36_png.png](https://qiita-image-store.s3.amazonaws.com/0/15267/45630581-77d9-dd85-04c4-3c7f4ea60960.png "2015-03-10_17_00_36_png.png")

```WordBalloonView.java
public class WordBalloonView extends RelativeLayout {

    @InjectView(R.id.txt_balloon)
    TextView mTxtBalloon;

    private String balloonText;

    public WordBalloonView(Context context, AttributeSet attrs) {
        super(context, attrs);
        inflate(context, R.layout.ui_word_balloon, this);
        ButterKnife.inject(this);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.WordBalloonView);
        try {
            balloonText = a.getString(R.styleable.WordBalloonView_balloonText);
        } finally {
            a.recycle();
        }

        mTxtBalloon.setText(balloonText);
    }

    public void setBalloonText(String balloonText) {
        this.balloonText = balloonText;
        mTxtBalloon.setText(balloonText);
    }

}
```

```xml
<com.konifar.whovoice.views.WordBalloonView
    android:id="@+id/balloon_word"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />
```

詳しいカスタムビューの作り方は、[Androidで独自Viewを作るときの4つのTips](http://qiita.com/kikuchy/items/0fa6bd232930bb12e187)が参考になります。

----

以上！他にいい方法があれば教えてください。