VectorDrawable対応まとめ

  • 131
    いいね
  • 2
    コメント
この記事は最終更新日から1年以上が経過しています。

2016/04/12(火)追記

23.3.0から、 app:srcCompatsetImageResouce()でしかVectorDrawableが適用されなくなったようです。詳しくはSupport Vector Drawableのバージョン間差異についてに詳しく書かれています。


DroidKaigi公式アプリのアイコンをVectorDrawableにして各解像度ごとのpngファイルをほとんど消すことができたので、対応した内容をまとめておこうと思います。
Suppoort vector drawable #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

VectorDrawableの作成

Vector Asset Studioなどを使って既存のアイコンと同じVectorDrawableを作っていきます。詳しくは以下を参照してください。

既存のアイコンからVectorDrawableを作る

対応箇所

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

1. ImageViewのandroid:src

xmlの中のandroid:srcapp:srcCompatに変えるだけです。

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

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

imageView.setImageResource(R.drawable.ic_search);

2. TextViewのandroid:drawableLeft

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

<?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です。

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

7. GoogleMapのマーカー

BitmapDescriptorFactory.fromResource()を使うと落ちます。
一度Bitmapに変換して、fromBitmap()を使って対応しました。
VectorDrawableをBitmapに変換する

8. Drawableを指定するUIライブラリ

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

VectorDrawableの属性の説明

主要な属性をまとめておきます。詳しくは公式のVectorDrawableのリファレンスを見てください。

タグ 属性 説明
vector android:width 表示する横幅。dpで指定します。
vector android:height 表示する縦幅。dpで指定します。
vector android:viewportWidth 書き出したVectorの横幅px。px(数値)で指定します。
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

AppCompat v23.2 — Age of the vectorsによると、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が適応されるまでの仕組み

これからはVectorDrawableにすべきなの?

Vectorにすべきなんじゃないでしょうか。
最近のGoogleのOSS plaidも、全てVectorDrawableで作られていますね。

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

命名や置き場所はどうするべき?

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

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

2. Support LibraryのVectorDrawableCompatが適応されるまでの仕組み

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

3. VectorDrawableリファレンス

VectorDrawableの属性やメソッドが全てまとまっています。

4. Vector Asset Studio

svgファイルからVectorDrawableを作成するAndroidStudioのツールの説明です。

5. plaid

Googleの中の人が作っているOSSです。アイコンは全てVectorDrawableで作られています。