web-dev-qa-db-ja.com

古いAndroidバージョンのレイヤーリストで描画可能なベクター

新しいAndroidバージョンでは、次のコード:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item>
            <shape Android:shape="oval">
                <solid Android:color="#bdbdbd" />
                <size
                    Android:width="60dp"
                    Android:height="60dp" />
            </shape>
    </item>
    <item
        Android:drawable="@drawable/ic_library_books_black_24dp"
        Android:gravity="center"
        Android:width="40dp"
        Android:height="40dp"
        >
    </item>
</layer-list>

これを完璧に生成します:

Vector drawable showing white lists on grey circular background

しかし、以前のAndroidバージョン(私がテストしたものからのAPI 16および19)は、これがまったく好きではなく、

E/AndroidRuntime: FATAL EXCEPTION: main
              Process: package.app, PID: 11490
              Android.view.InflateException: Binary XML file line #26: Error inflating class ImageView

インフレ時に。すべてのImageViewにapp:srcCompatを使用しているので、問題はありません。

標準のベクターDrawableも正常に機能しますが、layer-listに配置すると混乱が生じます。回避策はありますか?

30
Semdog

レイヤーリスト内のベクトルドロアブルの幅/高さ属性は、API 23(Marshmallow)以降でのみサポートされています。 Android Studioエディターでレイヤーリストのドロアブルを見ると、これらの属性の周りに黄色のブロックがあり、古いデバイスでは確実に機能しないという警告が表示されます。

しかし、警告を取り除き、次のような同じセンタリング効果を達成できると思います。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item>
        <shape Android:shape="oval">
            <solid Android:color="#bdbdbd" />
            <size
                Android:width="60dp"
                Android:height="60dp" />
        </shape>
    </item>
    <item
        Android:drawable="@drawable/ic_library_books_black_24dp"
        Android:top="10dp"
        Android:bottom="10dp"
        Android:left="10dp"
        Android:right="10dp">
    </item>
</layer-list>

これを古いAPI 15の電話でテストしましたが、うまくいきました。これがあなたにも役立つことを願っています。

更新:

この回答の以前のバージョンでは、vectorDrawables.useSupportLibrary = trueをレイヤーリストで使用しないことをお勧めしました。クラッシュを引き起こすためです。ただし、クラッシュを修正するように思われる回避策について最近学びました(@ Android developerが正しく言及されている、自動生成された太ったpngファイルを回避します)。正しく機能するために何をする必要があるのか​​を以下に要約します。

xmlで必ずsrcCompatを使用してください。

    <Android.support.v7.widget.AppCompatImageView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    app:srcCompat="@drawable/layer_list_with_svg" />

'vectorDrawables.useSupportLibrary'をapp/build.gradleに追加

 Android {
   defaultConfig {
     vectorDrawables.useSupportLibrary = true
   }
 }

'setCompatVectorFromResourcesEnabled(true)'をonCreateに追加

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
    setContentView(R.layout.activity_main);
}

なぜこれがすべて必要なのですか?

より知識のある人が私に説明したように、これはAndroidが互換性のあるベクトルDrawableをロードする方法と関係しています。vectorDrawables.useSupportLibrary = trueを使用している場合、画像ビューはVectorDrawableCompatをロードしますapp:srcCompatを使用する場合のドロウアブル。レイヤーリストドロウアブルが膨張している場合、それらの参照ベクトルドロウアブルの作成方法を把握する方法はありません。しかし、setCompatVectorFromResourcesEnabledをオンにすると、画像ビューとそのapp:srcCompat属性よりもはるかに低いレベルであるため、レイヤーリストで参照されるベクタードロウアブルをロードする方法を把握できます。

27

この回答は、Chris Banes(サポートライブラリで作業している)の記事 AppCompat-Vector of Vectors に基づいています。この質問については、「The magic 'way」というタイトルのセクションに注目しています。

あなたが経験しているクラッシュは、サポートライブラリがデフォルトでVectorDrawablesを使用するsome方法のみを許可し、layer-listがそれらの1つではないためです。

アクティビティの一番上に追加して、<layer-list>などの他のVectorDrawableの使用を有効にすることができる特定のコードブロックがあります。

static {
    AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
}

注:リンクされた記事には、このメソッド名に「FromSources」を使用した誤字が含まれています。上記のように「FromResources」である必要があります。

このようなドロアブルを使用する各アクティビティにこれを追加するか、他のアクティビティの拡張元であるBaseActivityクラスに含める必要があります。

記事によれば、これは以下が機能することを意味するはずです。

ベクターリソースのみを含む他のドロウアブルリソースを参照するDrawableContainers。

... StateListDrawable ... InsetDrawable、LayerDrawable、LevelListDrawable、およびRotateDrawable。

ただし、このメソッドは「may」という単語と重く、これは動作する可能性があり、デフォルトでは有効になっていないため、実際に動作していることに注意して確認してくださいあなたのために!

実際、この質問には別の側面があり、他のユーザーへのクレジットSelim AjimiおよびRapunzel Van Winkle回答でこれに対処します。 <layer-list>は、APIの間でいくつかの異なる動作を持ちます。特に、<item>widthおよびheight属性は、API 23+でのみサポートされます。これはクラッシュの原因ではなく、アプリがクラッシュすることもありませんが、以前のAPIで機能するとイメージが意図したとおりに表示されないことを意味します。

Rapunzel Van Winkleからの提案は、実際にAPI全体でドロウアブルを正しく配置する良い方法のようです(API 16および24でテスト済み):

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item>
        <shape Android:shape="oval">
            <solid Android:color="#bdbdbd" />
            <size
                Android:width="60dp"
                Android:height="60dp" />
        </shape>
    </item>
    <item
        Android:drawable="@drawable/ic_library_books_black_24dp"
        Android:top="10dp"
        Android:bottom="10dp"
        Android:left="10dp"
        Android:right="10dp"
        >
    </item>
</layer-list>
9
Lewis McGeary
<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:Android="http://schemas.Android.com/apk/res/Android" >
    <item
        Android:drawable="@[package:]drawable/drawable_resource"
        Android:id="@[+][package:]id/resource_name"
        Android:top="dimension"
        Android:right="dimension"
        Android:bottom="dimension"
        Android:left="dimension" />
</layer-list>

ご覧のとおり here には幅/高さの属性がありません...

あなたはアイテムにビットマップを追加することができますこれは最良の解決策だと思います

1
Selim Ajimi

古いAndroidバージョンでのVectorDrawbleのサポートは かなり制限されています です。vectorDrawables.useSupportLibrary = trueを使用すると仮定します:

Android 5.0(APIレベル11)以降を実行しているすべてのデバイスでVectorDrawableCompatをAPIレベル7およびAnimatedVectorDrawableCompatに戻すことができます。方法Android XMLファイルなど、Drawable IDを受け入れるすべての場所でベクターDrawableのロードがサポートされていますAndroid.support.v7.appcompatパッケージには、ベクターDrawableを使いやすくするための多くの機能が追加されています。 ImageViewまたはImageButtonやFloatingActionButtonなどのサブクラスを含む.support.v7.appcompatパッケージでは、新しいapp:srcCompat属性を使用して、ベクターのドロアブルとAndroid:srcで利用可能な他のドロアブルを参照できます。

コードでも、制限があります:

実行時にドロアブルを変更するには、以前と同様にsetImageResource()メソッドを使用できます。 AppCompatとapp:srcCompatを使用することは、ベクタードロウアブルをアプリに統合する最も確実な方法です。

何ができる?

可能な解決策はほとんどありません:

  1. layerDrawableで使用するVectorDrawableの代替ドローアブルがあります。たとえば、res/drawable-xxhdpiに配置し、VectorDrawableをres/drawable-anydpiに配置します。

  2. アプリにVectorDrawableを使用できるminSdkがあるまで、vectorDrawables.useSupportLibrary = trueを使用しないでください。 IDEはPNGファイルを生成するため、これは機能します。

  3. layerListをプログラムで作成し(例 here )、VectorDrawableを配置するには、AppCompatResources.getDrawableを使用します。 VectorDrawableを配置する部分を除き、XMLを使用してそれを行うこともできます。

ところで、それが制限されている理由は、Googleが効率的で問題なくそれを実現できなかったことです。 AppCompatDelegate.setCompatVectorFromResourcesEnabled(true)を使用することで、完全にサポートするという当初の試みに到達できますが、ドキュメントにあるように、 [risk here

この機能を有効にすると、メモリ使用量の問題や構成インスタンスの更新の問題が発生する可能性があるため、この機能はデフォルトで無効になっています。構成を手動で更新する場合、おそらくこれを有効にしたくないでしょう。 あなたは警告を受けました

1