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 日:初始帖子




