Custom Viewsで複数のviewを１つにまとめて部品化する

##問題

- アプリ内に同じような表示箇所が複数あり、それぞれを修正するのが辛い:fearful:
- 下記のような、複数の場所で表示するパーツ

<img width="100" alt="スクリーンショット 2017-09-06 17.32.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/36517/6d9e9dc3-55c2-a360-d2b0-fec13bd28c01.png">

----
##解決案
- 複数のviewを１つのクラスにまとめて、表示ロジックもそのクラス内で完結させたい。
- Custom Viewを使う。
- 今回はRelativeLayoutを継承したクラスを作る。

--- 
##Custom Viewとは
[Creating Custom Views](https://developer.android.com/training/custom-views/index.html)

- 既存のviewをカスタマイズして使いやすいようにする。
- 例えば、正方形の画像が欲しい時はImageViewをextendsしたクラスを作成してonMeasure()をオーバライドする。
- レイアウトXMLをコピペして作ってる箇所は置き換えられるかもしれません。

---
##修正ファイル
- レイアウトXML
- viewをextendsしたクラス
- Activityのクラス
- ActiivtyのレイアウトXML
- attrs.xml （レイアウトXMLから値を取得したい場合。これは今回は説明しません。）

---
##レイアウトXML
- XMLを作成します。

```custom_image_view.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- mergeで不必要なviewGrouの階層を作らないようにする -->
<merge
    xmlns:android="http://schemas.android.com/apk/res/android">

    <ImageView
        android:id="@+id/icon"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="12dp"
        />

    <TextView
        android:id="@android:id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <TextView
        android:id="@+id/description"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</merge>

```

---
##viewをextendsしたクラス
```CustomImageView.java
public class CustomImageView extends RelativeLayout {
    private Context mContext;

    <!-- コンストラクタは3つ用意しました。 API21からは4つのコンストラクタが使えるようです-->
    public CustomImageView(Context context) {
        this(context, null);
    }

    public CustomImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        mContext = context;

        LayoutInflater inflater = LayoutInflater.from(context);
        inflater.inflate(R.layout.custom_image_view, this, true);
    }

    public void setInfo(String title, String description, String imageUrl) {
        ImageView imageView = findViewById(R.id.icon);
        
        Glide.with(getApplicationContext())
                .load(imageUrl)
                .placeholder(R.drawable.placeholder)
                .into(imageView);

        ((TextView) findViewById(R.id.title)).setText(title);
        ((TextView) findViewById(R.id.description)).setText(description);
        invalidate();
    }
}

```

---
##customViewを利用するActivityのクラス

``` MainActivity.java

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        CustomImageView custom = (CustomImageView) this.findViewById(R.id.custom);
        custom.setInfo("title", "description", "画像URL");
    }
}

```
----
##ActivityのレイアウトXML
``` activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <sample.com.test_customview.CustomImageView
        android:id="@+id/custom"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

</LinearLayout>

```

---
##終わりに
- 見た目や処理を１つにまとめられるので便利です。

---
## 参考資料
- [Android Pattern Cookbook マーケットで埋もれないための差別化戦略](http://book.impress.co.jp/books/1113101126)