Android ImageView 和 Drawable 支持 SVG
本文介绍了自定义类 SvgImageView 和 SvgDrawable,它们允许像使用其他图像一样使用 SVG 图像。
引言
本文介绍了如何在 Android 中使用 SVG 图像。目标是像使用其他图像一样使用 SVG 图像,使用 Drawable
和 ImageView
类。为此引入了新类:SvgDrawable
和SvgImageView
。
这些类支持所有 Android 图像缩放类型:fitXY
、fitStart
、fitEnd
、centerCrop
等。重要的是,**图像在光栅化之前以矢量格式拉伸**。我相信这能提高整体性能。
背景
建议您在此之前阅读 文章,作者是Igor Kushnarev 。Carl D. Worth、Anton Persson 和 Igor Kushnarev 做出了出色的工作。本文是他们工作的延续。
我需要更改他们的实现,原因如下:
- 实际上,很多(如果不是全部)SVG 图像都有所需的宽度和高度。它们写在文件中。我也想使用它们。原始实现不关心 SVG 的宽度和高度。
- 我需要一个
Drawable
类来处理图像,而不仅仅是ImageView
。因为Drawable
可以在许多其他 Android 类中使用。 - 我想利用图像的缩放类型:
fitXY
、fitStart
、fitEnd
、centerCrop
等。 FitXY
缩放类型需要对图像进行非均匀缩放。这是必需的,但原始原生代码不支持。- 我不想在 SVG
Drawable
的情况下,让标准的ImageView
类**缩放光栅化后的位图**。我希望矢量图像在光栅化之前根据缩放类型进行缩放。这将提高图像的性能和质量。
必备组件
好了,如果您已经阅读了 Igor Kushnarev 的 文章,您应该已经拥有这个了。
- 支持 Java、Android 和 CDT 的 Eclipse
- Android SDK
- Android NDK
- Sequoyah Android Native Support in Eclipse
关注点
SVG 图像的宽度和高度
请查看 /jni/libsvg-android/svg_android.c。
我向 Java 类 SvgRaster
添加了两个返回 SVG 图像宽度和高度的函数。
Java_com_libsvg_SvgRaster_svgAndroidGetWidth()
,Java_com_libsvg_SvgRaster_svgAndroidGetHeight()
.
它们使用 DOM 模型中的值,这些值是在解析 XML 结构时设置的。
缩放支持
我从两种基本方法中选择来实现 Android 缩放类型支持:
- 重写整个
ImageView
类。因为它专为光栅位图编写,所以需要付出巨大的努力来进行矩阵变换,而不让Drawable
本身来处理缩放。 - 在
ImageView
类上“作弊”。让它相信Drawable
具有合适的大小,并且不应该使用 Matrix 变换进行缩放。让 SVG 图像在光栅化之前以矢量方式进行缩放。
我选择了第二种方法,因为它更容易。
在 ImageView
类准备矩阵变换之前,我们让 SvgDrawable
根据 scaleType
调整其宽度和高度以匹配 ImageView
中的尺寸。
为此,我们重写了 setScaleType()
、setImageDrawable()
和 onSizeChanged()
。
@Override
public void setScaleType (ImageView.ScaleType scaleType) {
super.setScaleType(scaleType);
if (! mIsSvg) {
return;
}
SvgDrawable svg = (SvgDrawable) getDrawable();
// Let SVG scale itself!
super.setImageDrawable(null);
svg.setScaleType(scaleType);
int vWidth = getWidth() - getPaddingLeft() - getPaddingRight();
int vHeight = getHeight() - getPaddingTop() - getPaddingBottom();
svg.adjustToParentSize(vWidth, vHeight);
super.setImageDrawable(svg);
}
请注意,我们首先调用 super.setImageDrawable(null)
。然后我们更改 SVG 图像的缩放。然后通过 super.setImageDrawable(svg)
返回它。这个技巧奏效了!
SvgDrawable 类
这是一个基于 Igor Kushnarev 想法的相当简单的实现。
缩放支持需要新的函数
public void adjustToParentSize(int vWidth, int vHeight)
当 onSizeChanged()
、setScaleType()
和加载时,它从 SvgImageView
调用。
另外请注意,我们在 onBoundsChange()
中选择如何渲染 SVG 图像。
- 使用非均匀缩放 -
SvgRaster.svgAndroidRenderToArea()
- 使用均匀缩放 -
SvgRaster.svgAndroidRenderToAreaUniform
libsvgandroid 中的非均匀缩放支持
请查看 /jni/libsvg-android/svg_android_render.c。
我已更改函数
svg_status_t svgAndroidRenderToArea(JNIEnv *env,
svg_android_t *svg_android, jobject android_canvas, int x, int y, int w, int h) {
...
svg_android->fit_to_area = -1;
svg_android->fit_uniform = 0;
...
return svg_render (svg_android->svg, &SVG_ANDROID_RENDER_ENGINE, svg_android);
}
svg_android->fit_uniform
是一个新添加的成员,用于:_svg_android_set_viewport_dimension()
。
在 svgAndroidRenderToArea()
中,它设置为零(false
)。
在 svgAndroidRenderToAreaUniform()
中,它设置为 -1(true
)。
使用 SvgImageView
请查看 /res/layout/main2.xml。
该文件的一部分
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/TableView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:stretchColumns="1">
<TableRow
android:layout_weight="1.0"
android:layout_height="fill_parent">
<com.libsvg.SvgImageView
android:src="@drawable/smile01"
android:background="#FF806440"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:scaleType="fitXY"
/>
<com.libsvg.SvgImageView
android:src="@drawable/smile02"
android:background="#FF758040"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="center"
android:scaleType="fitStart"
/>
请注意 <com.libsvg.SvgImageView>
标签。它们拥有标准 ImageView
的所有属性。
结果
编译并成功运行后,您应该会看到表格中笑脸的图片。
表格有两行,每行有 3 张图片。

它演示了 SVG 图像的不同缩放类型。
目前,从左到右,从上到下:fitXY
、fitStart
、fitEnd
、centerCrop
、center
、centerInside
结论
希望本文能帮助改进 Android 开发。如果您有任何要添加的内容,请在此处写下并分享您的代码!
--
您真诚的,
Pavel B. Chernov
历史
- 2010 年 12 月 14 日:初始帖子