当前位置: 首页 > 知识库问答 >
问题:

为什么我的矢量绘制缩放不如预期?

萧韬
2023-03-14

我正在尝试在我的Android应用程序中使用矢量绘图。从…起http://developer.android.com/training/material/drawables.html(我的重点):

在Android 5.0(API Level 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
    android:layout_width="400dp"
    android:layout_height="400dp"
    android:src="@drawable/icon_bell"/>

当试图以400dp的速度显示图标时(在大约2015年运行Lollipop的大型高分辨率移动设备上),会产生模糊图像:

将矢量绘图定义中的宽度和高度更改为200dp可以显著改善400dp渲染大小的情况。然而,将其设置为TextView元素的可绘制图标(即文本左侧的图标)现在会创建一个巨大的图标。

我的问题是:

1) 为什么矢量绘图中有宽度/高度规格?我认为它们的全部意义在于它们无损地上下缩放,使得宽度和高度在定义上毫无意义?

2) 有没有可能使用一个单一的矢量绘图工具,它可以在TextView上作为24dp绘图工具工作,但可以很好地扩展以使用更大的图像?例如,我如何避免创建多个不同大小的矢量绘图,而是使用一个可根据渲染要求缩放的矢量绘图?

3) 如何有效地使用宽度/高度属性,以及与视口宽度/高度的区别是什么?

其他详情:

  • 设备正在运行API 22
  • 使用Android Studio v1。5.1和Gradle版本1.5。0
  • 清单是编译和目标级别23,最小级别15。我也尝试过将最小级别移动到21,但这没有什么不同
  • 反编译APK(最小级别设置为21)会在drawable文件夹中显示一个XML资源。不生成光栅化图像

共有3个答案

袁卓
2023-03-14

AppCompat 23.2为所有运行Android 2.1及以上版本的设备引入矢量绘图功能。图像可以正确缩放,不考虑矢量绘图XML文件中指定的宽度/高度。不幸的是,此实现没有在API级别21及更高版本中使用(有利于本机实现)。

好消息是,我们可以强制AppCompat在API级别21和22上使用其实现。坏消息是我们必须使用反射来实现这一点。

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

android {
  defaultConfig {
    vectorDrawables.useSupportLibrary = true
  }
}

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

然后,调用useCompatVectorIfNeed();在您的应用程序的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();
        }
    }
}

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

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

你的矢量绘图现在应该可以正确缩放了!

刁俊人
2023-03-14

1) 为什么矢量绘图中有宽度/高度规格?我认为它们的全部意义在于它们无损地上下缩放,使得宽度和高度在定义上毫无意义?

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

2) 有没有可能使用一个单一的矢量绘图工具,它可以作为文本视图上的24dp绘图工具,也可以是一个大的近屏幕宽度的图像?

我不相信这是可能的,如果你还需要目标SDK小于21。

3) 如何有效地使用宽度/高度属性,以及与视口宽度/高度的区别是什么?

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

Android:宽度

用于定义可绘制图形的固有宽度。这支持所有尺寸单位,通常用dp指定。

android:height

用于定义可绘制图形的固有高度。这支持所有尺寸单位,通常用dp指定。

android:viewportWidth

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

android:viewportHeight

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

更多文档:

Android 4.4(API级别20)和更低版本不支持矢量绘图。如果您的最低API级别设置为这些API级别之一,Vector Asset Studio还会指示Gradle生成矢量绘图的光栅图像,以实现向后兼容。您可以将矢量资产称为Java代码中的Drawable或XML代码中的@Drawable;当您的应用程序运行时,根据API级别自动显示相应的矢量或栅格图像。

编辑:有些奇怪的事情正在发生。以下是我在emulator SDK版本23中的结果(Lollipop测试设备现在已经死了…):

在emulator SDK版本21中:

堵龙野
2023-03-14

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

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

看起来使用android:scaleType=“fitXY”可以在Lollipop上正确缩放。

来自谷歌工程师:

您好,请告诉我scaleType='fitXY'是否可以作为您的解决方案,以使图像看起来清晰。

MarshmallowVsLollipop是由于Marshmallow中添加了一种特殊的除垢处理。

另外,对于您的评论:“正确的行为:vector drawable应该在没有质量损失的情况下进行缩放。因此,如果我们希望在应用程序中以3种不同的大小使用相同的资产,我们不必使用不同的硬编码大小将vector_drawable.xml复制3次。”

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

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

 类似资料:
  • 问题内容: 我有大型数据集(10 Hz数据,因此每24小时需要864k点),需要实时绘制。这个想法是用户可以缩放和平移到高度详细的散点图。 数据不是很连续,并且存在峰值。由于数据集太大,因此每次刷新图时我都无法绘制每个点。 但是我也不能只画出第n个点,否则我会错过主要特征,例如大而短的尖峰。 Matlab做得对。您可以给它一个全为零的864k向量,只需将任何一个点设置为1,它就会通过缩放和平移实时

  • 问题内容: 我正在学习线性代数课程,我想可视化正在使用的向量,例如向量加法,法向向量等。 例如: 在这种情况下,我想绘制3个向量。 然后,我应该能够添加V1,V2来绘制一个新的向量V12(全部合并在一个图中)。 当我使用以下代码时,情节与预期不符 问题答案: 多亏了每个人,您的每个帖子对我都有很大帮助。 对于我的问题,rbierman代码非常简单,我做了一些修改,并创建了一个函数来绘制给定数组中的

  • 在我的应用程序中,我必须为通知设置一个大图标。LargeIcon必须是位图,我的可绘制内容是矢量图像(Android中的新功能,请参见此链接)。问题是,当我尝试解码矢量图像资源时,返回空值。 以下是代码示例: 在本示例中,当我替换R.drawable时。vector_menu_objectifs带有“普通”图像,例如png,结果不为空(我得到了正确的位图)是否缺少什么?

  • 我想绘制以按钮为中心的缩放SVGPath节点。按钮应该保持其大小与图像大小无关,SVGPaths应该保留它们的相对位置。 问题是按钮图像被移位了。

  • 我使用的是23.4版的设计支持库。0.我已启用渐变标志: 我正在使用构建工具23.0版。2,但我仍然在KitKat或更低版本上获得。 当我使用或。 是的,我在每一个我使用抽绳的活动中都会用到这个 这是支持库的错误吗?

  • 当我运行这个代码时,我看不到椭圆形,我只能看到一个空白的框架。我知道我可以使用方法,但我很想知道为什么我的代码不能工作。