VectorDrawable対応まとめ

# 2016/04/12（火）追記
23.3.0から、 `app:srcCompat`と`setImageResouce()`でしかVectorDrawableが適用されなくなったようです。詳しくは[Support Vector Drawableのバージョン間差異について](http://qiita.com/androhi/items/7398c7d7c5b07d14ab01)に詳しく書かれています。

----
DroidKaigi公式アプリのアイコンをVectorDrawableにして各解像度ごとのpngファイルをほとんど消すことができたので、対応した内容をまとめておこうと思います。
[Suppoort vector drawable #345](https://github.com/konifar/droidkaigi2016/pull/345)


# 下準備

## 1. Gradleの設定
gradleのbuild toolバージョンをv2.0に上げます。

```build.gradle
buildscript {
    ...
    dependencies {
        ...
        classpath 'com.android.tools.build:gradle:2.0.0-beta6'
        ...
    }
}
```

build.gradleのdefaultConfigに以下を追加します。

```build.gradle
android {
  ...
  defaultConfig {
    ...
    vectorDrawables.useSupportLibrary = true
    ...
  }
}
```

もしbuild tool v1.5.0以下を使い続けなければならない場合は、以下のように記述します。

```
android {
  defaultConfig {
    // Stops the Gradle plugin’s automatic rasterization of vectors
    generatedDensities = []
  }
  // Flag to tell aapt to keep the attribute ids around
  aaptOptions {
    additionalParameters "--no-version-vectors"
  }
}
```

## 2. Support Libraryのアップデート
appCompatのバージョンを23.2.0に上げます。
`support-vector-drawable`は明示的に追加しなくても大丈夫です。

```build.gradle
dependencies {
    ...
    compile "com.android.support:appcompat-v7:23.2.0"
    compile "com.android.support:support-vector-drawable:23.2.0"
    compile "com.android.support:animated-vector-drawable:23.2.0"
    ...
}
```

詳しくは、以下の記事が詳しいので参考にしてください。
[AppCompat v23.2 — Age of the vectors]
(https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88)


# VectorDrawableの作成
[Vector Asset Studio](http://developer.android.com/intl/ja/tools/help/vector-asset-studio.html)などを使って既存のアイコンと同じVectorDrawableを作っていきます。詳しくは以下を参照してください。

[既存のアイコンからVectorDrawableを作る](http://qiita.com/konifar/items/a82fb45746ca6380299c)


# 対応箇所
ImageViewの`anodroid:src`やTextViewの`anodroid:drawableLeft`、Notificationのiconなど、それぞれどう対応していったのかをまとめます。

## 1. ImageViewのandroid:src
xmlの中の`android:src`を`app:srcCompat`に変えるだけです。

```
<ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/ic_search"/>
```

コードで指定する場合は、`setImageResource`を使えばOKです。

```java
imageView.setImageResource(R.drawable.ic_search);
```

## 2. TextViewのandroid:drawableLeft
TextViewの場合は、直接VectorDrawableを指定すると落ちます。
そのため、StateListDrawableを作成してその中でVectorDrawableを指定してあげる必要があります。

```xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/ic_access_time_grey_500_12dp_vector" />
</selector>
```

```
<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawableLeft="@drawable/ic_access_time_grey_500_12dp_vector_state"
    android:drawablePadding="@dimen/icon_spacing_small"
    android:drawableStart="@drawable/ic_access_time_grey_500_12dp_vector_state"
```

## 3. ContextCompat.getDrawable()
何もしなくてOKです。AppCompat23.2.0からは内部のアイコンもVectorDrawableを使っていますし、基本的に~Compatクラスを使っていれば何も対応はいらないはずです。

## 4. android.support.design.widget.NavigationView
menuの中の`android:icon`にVectorDrawableを指定すればそのまま動きます。

```drawer_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_all_sessions"
            android:icon="@drawable/ic_event_note_grey_600_24dp_vector"
            android:title="@string/all_sessions" />
        ...
    </group>

</menu>
```

## 5. Toolbarのメニューアイコン
AppCompatActivityを使っていれば、VectorDrawableを指定するだけでOKです。

```menu_sessions.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/item_search"
        android:icon="@drawable/ic_search_white_24dp_vector"
        android:orderInCategory="100"
        android:title="@string/search"
        app:showAsAction="always" />

</menu>
```

## 6. Notificationのアイコン
***Lollipop未満はまだ未対応です。***
Lollipop以上はdrawable-v21ディレクトリに入れたVectorDrawableを指定するだけでOKです。

```java
Notification notification = new NotificationCompat.Builder(context)
    .setContentIntent(pendingIntent)
    .setSmallIcon(R.drawable.ic_stat_notification_vector)
    ...
```

## 7. GoogleMapのマーカー
`BitmapDescriptorFactory.fromResource()`を使うと落ちます。
一度Bitmapに変換して、`fromBitmap()`を使って対応しました。
[VectorDrawableをBitmapに変換する](http://qiita.com/konifar/items/aaff934edbf44e39b04a)

## 8. Drawableを指定するUIライブラリ
内部でBitmapDrawableにキャストしていたりすると落ちます。
もし対応していない場合は、ライブラリにPullRequestを送って対応しましょう。
DroidKaigiアプリの場合、LikeButtonが対応していなかったのでPullRequestを送りました。
https://github.com/jd-alexander/LikeButton/pull/17


# VectorDrawableの属性の説明
主要な属性をまとめておきます。詳しくは[公式のVectorDrawableのリファレンス](http://developer.android.com/intl/ja/reference/android/graphics/drawable/VectorDrawable.html)を見てください。

|タグ| 属性 | 説明 |
|:--:|:--:|:--|
|vector|android:width| 表示する横幅。dpで指定します。 |
|vector|android:height| 表示する縦幅。dpで指定します。 |
|vector|android:viewportWidth| 書き出したVectorの横幅px。px（数値）で指定します。 |vector|
|vector|android:viewportHeight| 書き出したVectorの縦幅px。px（数値）で指定します。 |
|vector|android:autoMirrored| RTLで反転させるアイコンの場合、trueを指定します。 |
|path|android:fillColor| pathの色。透過は指定しても無視されます。 |
|path|android:fillAlpha| pathの透過度。0.0（透明）〜1.0を指定します。 |
|path|android:pathData| 画像のpath。 |

# 対応時に気になりそうなところ
以下対応時の雑感です。

## どのくらいapkサイズが減るの？
DroidKaigiアプリの場合、29個のアイコンをVectorDrawableに変えたことで、200KBほど減りました。
[Suppoort vector drawable #345](https://github.com/konifar/droidkaigi2016/pull/345)

[AppCompat v23.2 — Age of the vectors](https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88#.fzcft7z1w)によると、AppCompat自体も70KB減らせたらしいです。

> Allows AppCompat to use vector drawables itself. This itself has shaved off around 70KB from AppCompat’s AAR (~9%).

対応はめんどくさいところもありますが、アイコンの数だけ効果は出るという感じですね。

## どういう仕組みなの？
実際にVectorDrawableをどう解釈しているのかはわかりませんが、VectorDrawableCompatが適用されるまでの流れは以下に詳しくまとまっています。
[Support LibraryのVectorDrawableCompatが適応されるまでの仕組み](http://qiita.com/takahirom/items/c6f5a3204210d1e95c70)

## これからはVectorDrawableにすべきなの？
Vectorにすべきなんじゃないでしょうか。
最近のGoogleのOSS [plaid](https://github.com/nickbutcher/plaid)も、全てVectorDrawableで作られていますね。

色の変更も楽ですし、採用しない理由は特になさそうです。AndroidStudioのプレビューがまだうまく表示できてない部分がありますが、そのうち対応してくれるはずです。


## 命名や置き場所はどうするべき？
[plaid](https://github.com/nickbutcher/plaid)を真似て、drawableの中に入れることにしました。

ファイル名は、アイコンの場合は `ic_xxxx_vector.xml`のようにsuffixに`_vector`をつけることにしました。vector以外のアイコンも混在しているため、ぱっと見てVectorDrawableだとわかるようにしたかったからです。

TextViewのdrawableLeftなどで使うのにStateListDrawableを作る必要がある場合は、`ic_xxxx_vector_state.xml`のようにしました。ここはどうするべきかまだ決めかねています。



## 起動時のオーバーヘッドは？
内部を見てないので体感でしかないですが、特に感じませんでした。


## ビルド時間に影響はないの？
内部を見てないので体感でしかないですが、特に感じませんでした。



# 参考資料

####1. [AppCompat v23.2 — Age of the vectors](https://medium.com/@chrisbanes/appcompat-v23-2-age-of-the-vectors-91cbafa87c88)

基本的なVectorDrawable導入方法がまとまっています。

####2. [Support LibraryのVectorDrawableCompatが適応されるまでの仕組み](http://qiita.com/takahirom/items/c6f5a3204210d1e95c70)

内部でどのようにVectorDrawableCompatが適用されていくかが詳しく説明されています。

####3. [VectorDrawableリファレンス](https://developer.android.com/intl/ja/reference/android/graphics/drawable/VectorDrawable.html)
VectorDrawableの属性やメソッドが全てまとまっています。

####4. [Vector Asset Studio](http://developer.android.com/intl/ja/tools/help/vector-asset-studio.html)
svgファイルからVectorDrawableを作成するAndroidStudioのツールの説明です。

####5. [plaid](https://github.com/nickbutcher/plaid)
Googleの中の人が作っているOSSです。アイコンは全てVectorDrawableで作られています。