为什么我的矢量可绘制缩放不符合预期?

Chr*_*ght 85 scaling android vector drawable

我试图在我的Android应用程序中使用矢量drawables.来自http://developer.android.com/training/material/drawables.html(强调我的):

在Android 5.0(API Level 21)及更高版本中,您可以定义矢量drawable,可以在不丢失定义的情况下进行缩放.

使用这个drawable:

<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" />
Run Code Online (Sandbox Code Playgroud)

和这个ImageView:

<ImageView
    android:layout_width="400dp"
    android:layout_height="400dp"
    android:src="@drawable/icon_bell"/>
Run Code Online (Sandbox Code Playgroud)

尝试以400dp显示图标时(在大约2015年左右的移动设备上运行棒棒糖的高分辨率),会产生这种模糊的图像:

blurryBellIcon

将矢量drawable的定义中的宽度和高度更改为200dp可显着改善400dp渲染大小的情况.但是,将此设置为TextView元素的drawable(即文本左侧的图标)现在会创建一个巨大的图标.

我的问题:

1)为什么矢量可绘制中有宽度/高度规格?我认为这些问题的全部意义在于它们无损扩大和缩小,其宽度和高度在其定义中毫无意义?

2)是否可以使用单个矢量drawable,它在TextView上作为24dp可绘制,但可以很好地扩展以使用更大的图像?例如,我如何避免创建不同大小的多个矢量绘图,而是使用一个可以扩展到渲染要求的​​矢量绘图?

3)如何有效地使用width/height属性以及viewportWidth/Height的区别是什么?

额外细节:

  • 设备正在运行API 22
  • 将Android Studio v1.5.1与Gradle 1.5.0版一起使用
  • 清单是编译和目标级别23,最低级别15.我也尝试将最小级别移动到21,但这没有任何区别.
  • 解压缩APK(最小级别设置为21)在可绘制文件夹中显示单个XML资源.不会生成栅格化图像.

Tae*_*ark 94

这里有关于此问题的新信息:

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

看起来像使用 android:scaleType="fitXY"会让它在Lollipop上正确缩放.

来自Google工程师:

嗨,让我知道scaleType ='fitXY'是否可以为您解决方法,以使图像看起来更清晰.

棉花糖Vs棒棒糖是由于棉花糖中添加了特殊的结垢处理.

另外,对于你的评论:"正确的行为:矢量drawable应该扩展而没有质量损失.所以如果我们想在我们的应用程序中使用3种不同大小的相同资产,我们不必复制vector_drawable.xml 3次不同硬编码尺寸."

虽然我完全同意这应该是这样的,但实际上,Android平台存在性能问题,以至于我们还没有达到理想的世界.因此,如果您确定要在屏幕上同时绘制3种不同的大小,实际上建议使用3种不同的vector_drawable.xml以获得更好的性能.

技术细节基本上我们在钩子下使用位图来缓存复杂的路径渲染,这样我们就可以获得最佳的重绘性能,与重绘位图drawable相同.

  • 好吧谷歌,我们必须复制粘贴**相同的可绘制的相同的视口和路径**只有不同的大小是非常可怕的. (16认同)
  • @Harish Gyanani,android:scaleType="fitXY" 解决了问题,但是动态图标和非方形图标又如何呢? (2认同)

Cor*_*ton 25

1)为什么矢量可绘制中有宽度/高度规格?我认为这些问题的全部意义在于它们无损扩大和缩小,其宽度和高度在其定义中毫无意义?

对于小于21的SDK版本,其中构建系统需要生成光栅图像,并且在未指定宽度/高度的情况下作为默认大小.

2)是否可以使用单个矢量drawable,它在TextView上作为24dp可绘制,以及大的近屏宽度图像?

如果您还需要针对少于21的SDK进行定位,我认为这是不可能的.

3)如何有效地使用width/height属性以及viewportWidth/Height的区别是什么?

文档:(现在我重新阅读它实际上不是很有用......)

android:width

用于定义drawable的固有宽度.这支持所有维度单位,通常用dp指定.

android:height

用于定义drawable的内在高度.这支持所有维度单位,通常用dp指定.

android:viewportWidth

用于定义视口空间的宽度.视口基本上是绘制路径的虚拟画布.

android:viewportHeight

用于定义视口空间的高度.视口基本上是绘制路径的虚拟画布.

更多文档:

Android 4.4(API级别20)及更低版本不支持矢量绘图.如果您的最低API级别设置为其中一个API级别,Vector Asset Studio还会指示Gradle生成向量drawable的光栅图像以实现向后兼容性.您可以像Drawable在Java代码或@drawableXML代码中那样引用矢量资产; 当您的应用运行时,相应的矢量或光栅图像会根据API级别自动显示.


编辑:有些奇怪的事情正在发生.这是我在模拟器SDK版本23中的结果(Lollipop +测试设备现在已经死了......):

6.x上的好铃声

在模拟器SDK版本21中:

5.x上的蹩脚铃铛


use*_*008 9

AppCompat 23.2为所有运行Android 2.1及更高版本的设备引入了矢量绘图.无论vector drawable的XML文件中指定的宽度/高度如何,图像都能正确缩放.遗憾的是,此实现未在API级别21及更高版本中使用(有利于本机实现).

好消息是我们可以强制AppCompat在API级别21和22上使用它的实现.坏消息是我们必须使用反射来执行此操作.

首先,确保您使用的是最新版本的AppCompat,并且已启用新的矢量实现:

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

dependencies {
    compile 'com.android.support:appcompat-v7:23.2.0'
}
Run Code Online (Sandbox Code Playgroud)

然后,调用useCompatVectorIfNeeded();您的应用程序的onCreate():

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

最后,确保使用app:srcCompat而不是android:src设置ImageView的图像:

<ImageView
    android:layout_width="400dp"
    android:layout_height="400dp"
    app:srcCompat="@drawable/icon_bell"/>
Run Code Online (Sandbox Code Playgroud)

你的矢量drawables现在应该正确缩放!


小智 6

1)为什么矢量可绘制中有宽度/高度规格?我认为这些问题的全部意义在于它们无损扩大和缩小,其宽度和高度在其定义中毫无意义?

如果您没有在布局视图中定义它,这只是向量的默认大小.(即您使用换行内容作为imageview的高度和宽度)

2)是否可以使用单个矢量drawable,它在TextView上作为24dp可绘制,以及大的近屏宽度图像?

是的,只要正在运行的设备使用棒棒糖或更高级别,我就没有任何调整大小的问题.在以前的API中,在构建应用程序时,矢量将转换为用于不同屏幕大小的png.

3)如何有效地使用width/height属性以及viewportWidth/Height的区别是什么?

这会影响矢量周围空间的使用方式.即您可以使用它来更改视口内矢量的"重力",使矢量具有默认边距,将矢量的某些部分保留在视口之外等等...通常,您只需将它们设置为相同尺寸.


小智 5

我解决我的问题只是改变矢量图像的大小。从一开始它就是这样的资源:

<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">
Run Code Online (Sandbox Code Playgroud)

我已将其更改为 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">
Run Code Online (Sandbox Code Playgroud)

它对我有用。