web-dev-qa-db-ja.com

ベクトル描画可能スケーリングが期待どおりにならないのはなぜですか?

Androidアプリでベクタードロウアブルを使用しようとしています。 http://developer.Android.com/training/material/drawables.html (エンファシス鉱山)から:

Android 5.0(APIレベル21)以上では、定義を失うことなくスケーリングするベクトルドロアブルを定義できます。

このドロウアブルの使用:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:height="24dp"
Android:width="24dp"
Android:viewportWidth="24"
Android:viewportHeight="24">
<path Android:fillColor="@color/colorPrimary" Android:pathData="M14,20A2,2 0 0,1 12,22A2,2 0 0,1 10,20H14M12,2A1,1 0 0,1 13,3V4.08C15.84,4.56 18,7.03 18,10V16L21,19H3L6,16V10C6,7.03 8.16,4.56 11,4.08V3A1,1 0 0,1 12,2Z" />

このImageView:

<ImageView
    Android:layout_width="400dp"
    Android:layout_height="400dp"
    Android:src="@drawable/icon_bell"/>

400dpでアイコンを表示しようとすると、このぼやけた画像が生成されます(Lollipopを実行している2015年頃の大型の高解像度デバイスで):

blurryBellIcon

ベクトルDrawableの定義で幅と高さを200dpに変更すると、400dpのレンダリングサイズでの状況が大幅に改善されます。ただし、これをTextView要素の描画可能オブジェクト(テキストの左側のアイコン)に設定すると、巨大なアイコンが作成されます。

私の質問:

1)なぜベクターのドロアブルに幅/高さの指定があるのですかこれらの全体的なポイントは、定義で幅と高さを無意味にする無損失に拡大縮小することだと思いましたか?

2)TextViewで24dpのドロアブルとして機能する単一のベクトルドロアブルを使用することはできますか?例えば。異なるサイズの複数のベクトルDrawableの作成を回避し、代わりにレンダリング要件に合わせてスケーリングするものを使用するにはどうすればよいですか?

3)幅/高さ属性を効果的に使用するにはどうすればよいですか?また、viewportWidth/Heightとの違いは何ですか?

追加の詳細:

  • デバイスはAPI 22を実行しています
  • Gradleバージョン1.5.0でAndroid St​​udio v1.5.1を使用する
  • マニフェストはコンパイルされ、ターゲットレベル23、最小レベル15です。また、最小レベルを21に移動しようとしましたが、違いはありませんでした。
  • (最小レベルを21に設定した)APKを逆コンパイルすると、描画可能なフォルダーに単一のXMLリソースが表示されます。ラスタライズされた画像は作成されません。
81
Chris Knight

この問題に関する新しい情報がここにあります:

https://code.google.com/p/Android/issues/detail?id=202019

Android:scaleType="fitXY"を使用すると、Lollipopで正しくスケーリングされるようです。

Googleエンジニアから:

こんにちは、画像をシャープに見せるために、scaleType = 'fitXY'が回避策になるかどうか教えてください。

マシュマロ対ロリポップは、マシュマロに追加された特別なスケーリング処理によるものです。

また、コメントについて:「正しい動作:ベクトルドロウアブルは品質を損なうことなくスケーリングする必要があります。したがって、アプリケーションで3つの異なるサイズで同じアセットを使用する場合、vector_drawable.xmlを異なるサイズで3回複製する必要はありませんハードコードされたサイズ。」

私はこれが事実であるべきだと完全に同意しますが、実際には、Androidプラットフォームはパフォーマンスの問題を抱えており、理想的な世界にはまだ到達していません。したがって、画面上に同時に3つの異なるサイズを描画することが確実な場合は、パフォーマンスを向上させるために、実際には3つの異なるvector_drawable.xmlを使用することをお勧めします。

技術的な詳細は、基本的に、フックの下でビットマップを使用して複雑なパスレンダリングをキャッシュし、ビットマップドロアブルの再描画と同等の最高の再描画パフォーマンスを得ることができるようにすることです。

90
Taehyun Park

1)なぜベクターのドロアブルに幅/高さの指定があるのですかこれらの全体的なポイントは、定義で幅と高さを無意味にする無損失に拡大縮小することだと思いましたか?

ビルドシステムがラスターイメージを生成する必要がある21未満のSDKバージョンの場合、および幅/高さを指定しない場合のデフォルトサイズとして。

2)TextViewで24dpのドロアブルとして機能する単一のベクトルドロアブルと、画面に近い幅の大きな画像を使用できますか?

21未満のSDKもターゲットにする必要がある場合、これが可能だとは思わない。

3)幅/高さ属性を効果的に使用するにはどうすればよいですか?また、viewportWidth/Heightとの違いは何ですか?

ドキュメント: (実際に読み直した今ではあまり役に立たない...)

Android:width

ドロアブルの固有の幅を定義するために使用されます。これは、通常dpで指定されるすべてのディメンション単位をサポートします。

Android:height

ドロアブルの本質的な高さを定義するために使用されます。これは、通常dpで指定されるすべてのディメンション単位をサポートします。

Android:viewportWidth

ビューポートスペースの幅を定義するために使用されます。ビューポートは、基本的にパスが描画される仮想キャンバスです。

Android:viewportHeight

ビューポート空間の高さを定義するために使用されます。ビューポートは、基本的にパスが描画される仮想キャンバスです。

その他のドキュメント:

Android 4.4(APIレベル20)以前では、ベクトルドロアブルはサポートされていません。最小APIレベルがこれらのAPIレベルのいずれかに設定されている場合、Vector Asset Studioは、Gradleに下位互換性のためにベクトルDrawableのラスターイメージを生成するよう指示します。ベクトル資産は、JavaコードではDrawable、XMLコードでは@drawableとして参照できます。アプリを実行すると、対応するベクターまたはラスター画像がAPIレベルに応じて自動的に表示されます。


編集:何か変なことが起こっています。エミュレータSDKバージョン23での私の結果は次のとおりです(Lollipop +テストデバイスは現在動作していません...):

Good bells on 6.x

そして、エミュレータSDKバージョン21では:

Crappy bells on 5.x

25
Cory Charlton

AppCompat 23.2では、Android 2.1以降を実行しているすべてのデバイスにベクタードロウアブルが導入されています。ベクタードロウアブルのXMLファイルで指定された幅/高さに関係なく、画像は正しくスケーリングされます。残念ながら、この実装はAPIレベル21以降では使用されません(ネイティブ実装が優先されます)。

良いニュースは、AppCompatにAPIレベル21および22での実装の使用を強制できることです。悪いニュースは、これを行うためにリフレクションを使用する必要があることです。

まず、AppCompatの最新バージョンを使用していること、および新しいベクター実装を有効にしていることを確認してください。

Android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
    compile 'com.Android.support:appcompat-v7:23.2.0'
}

次に、アプリケーションのonCreate()でuseCompatVectorIfNeeded();を呼び出します。

private void useCompatVectorIfNeeded() {
    int sdkInt = Build.VERSION.SDK_INT;
    if (sdkInt == 21 || sdkInt == 22) { //vector drawables scale correctly in API level 23
        try {
            AppCompatDrawableManager drawableManager = AppCompatDrawableManager.get();
            Class<?> inflateDelegateClass = Class.forName("Android.support.v7.widget.AppCompatDrawableManager$InflateDelegate");
            Class<?> vdcInflateDelegateClass = Class.forName("Android.support.v7.widget.AppCompatDrawableManager$VdcInflateDelegate");

            Constructor<?> constructor = vdcInflateDelegateClass.getDeclaredConstructor();
            constructor.setAccessible(true);
            Object vdcInflateDelegate = constructor.newInstance();

            Class<?> args[] = {String.class, inflateDelegateClass};
            Method addDelegate = AppCompatDrawableManager.class.getDeclaredMethod("addDelegate", args);
            addDelegate.setAccessible(true);
            addDelegate.invoke(drawableManager, "vector", vdcInflateDelegate);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

最後に、app:srcCompatではなくAndroid:srcを使用してImageViewの画像を設定していることを確認してください。

<ImageView
    Android:layout_width="400dp"
    Android:layout_height="400dp"
    app:srcCompat="@drawable/icon_bell"/>

ベクターのドローアブルは正しくスケーリングされるはずです!

9
user3210008

1)なぜベクターのドロアブルに幅/高さの指定があるのですかこれらの全体的なポイントは、定義で幅と高さを無意味にする無損失に拡大縮小することだと思いましたか?

これは、レイアウトビューで定義しない場合のベクトルのデフォルトサイズです。 (つまり、imageviewの高さと幅にラップコンテンツを使用します)

2)TextViewで24dpのドロアブルとして機能する単一のベクトルドロアブルと、画面に近い幅の大きな画像を使用できますか?

はい、可能です。実行中のデバイスがLollipop以上を使用している限り、サイズ変更に問題はありません。以前のAPIでは、アプリをビルドすると、さまざまな画面サイズのベクターがpngに変換されます。

3)幅/高さ属性を効果的に使用するにはどうすればよいですか?また、viewportWidth/Heightとの違いは何ですか?

これは、ベクターの周囲のスペースの使用方法に影響します。つまり、ビューポート内のベクトルの「重力」を変更したり、ベクトルにデフォルトのマージンを持たせたり、ベクトルの特定の部分をビューポートから外したりするなどに使用できます。通常は、同じ値に設定しますサイズ。

6
emirua

私はこれらの方法を試してみましたが、残念ながら、どれも機能しませんでした。 fitXYImageViewを試して、app:srcCompatを使用しようとしましたが、使用することさえできません。しかし、私はトリックの方法を見つけました:

drawableをbackgroundImageViewに設定します。

しかし、この方法のポイントはビューの次元です。 ImageViewの寸法が正しくない場合、drawableはStretchを取得します。 Lollipop以前のバージョンで制御するか、一部のビューPercentRelativeLayoutを使用する必要があります。

役に立てば幸いです。

3
Mahdi Astanei

First:svgをdrawbleにインポート:(( https://www.learn2crack.com/2016/02/Android-studio-svg .html )))

描画可能フォルダを右クリックして、[新規]-> [ベクトルアセット]を選択します。

enter image description here

2- Vector Asset Studioには、組み込みのマテリアルアイコンまたは独自のローカルsvgファイルを選択するオプションがあります。必要に応じて、デフォルトのサイズをオーバーライドできます。

enter image description here

Second:Android AP​​I 7+からのサポートが必要な場合は、Android Support Library acordingを使用する必要があります(( https://stackoverflow.com/a/44713221/1140304 ))

1-追加

vectorDrawables.useSupportLibrary = true

build.gradleファイルに。

2- imageViewを持つレイアウトで名前空間を使用します。

xmlns:app="http://schemas.Android.com/apk/res-auto"

Third:imageViewをAndroid:scaleType = "fitXY"に設定し、app:srcCompatを使用します

 <ImageView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:scaleType="fitXY"
        app:srcCompat="@drawable/ic_menu" />

4番目:Javaコードにsvgを設定する場合、oncreate methoedの行の下に追加する必要があります

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

ベクトル画像のサイズを変更するだけで問題を解決できます。最初からそれは次のようなリソースでした:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:aapt="http://schemas.Android.com/aapt"
    Android:width="24dp"
    Android:height="24dp"
    Android:viewportHeight="300"
    Android:viewportWidth="300">

そして、私はそれを次のように150dp(このベクトルリソースのレイアウトのImageViewのサイズ)に変更しました:

<vector xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:aapt="http://schemas.Android.com/aapt"
    Android:width="150dp"
    Android:height="150dp"
    Android:viewportHeight="300"
    Android:viewportWidth="300">

それは私のために働いています。

1
Djek-Grif

私にとって、ベクターがpngに変換される原因は、ベクターDrawableのAndroid:fillType="evenodd"属性でした。 drawableでこの属性のすべてのオカレンスを削除した(デフォルトのnonzero塗りつぶしタイプを使用するベクトル)の場合、次回アプリをビルドしたときにすべてがうまくいきました。

0
Mahozad