65.9K
CodeProject 正在变化。 阅读更多。
Home

Android ImageView 和 Drawable 支持 SVG

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (11投票s)

2010年12月14日

CPOL

3分钟阅读

viewsIcon

160214

downloadIcon

5769

本文介绍了自定义类 SvgImageView 和 SvgDrawable,它们允许像使用其他图像一样使用 SVG 图像。

引言

本文介绍了如何在 Android 中使用 SVG 图像。目标是像使用其他图像一样使用 SVG 图像,使用 DrawableImageView 类。为此引入了新类:SvgDrawable SvgImageView

这些类支持所有 Android 图像缩放类型:fitXYfitStartfitEndcenterCrop 等。重要的是,**图像在光栅化之前以矢量格式拉伸**。我相信这能提高整体性能。

背景

建议您在此之前阅读 文章,作者是Igor Kushnarev Carl D. WorthAnton PerssonIgor Kushnarev 做出了出色的工作。本文是他们工作的延续。

我需要更改他们的实现,原因如下:

  • 实际上,很多(如果不是全部)SVG 图像都有所需的宽度和高度。它们写在文件中。我也想使用它们。原始实现不关心 SVG 的宽度和高度。
  • 我需要一个 Drawable 类来处理图像,而不仅仅是 ImageView。因为 Drawable 可以在许多其他 Android 类中使用。
  • 我想利用图像的缩放类型:fitXYfitStartfitEndcenterCrop 等。
  • 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 缩放类型支持:

  1. 重写整个 ImageView 类。因为它专为光栅位图编写,所以需要付出巨大的努力来进行矩阵变换,而不让 Drawable 本身来处理缩放。
  2. 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 张图片。

screenshot.jpg

它演示了 SVG 图像的不同缩放类型。

目前,从左到右,从上到下:
fitXYfitStartfitEnd
centerCropcentercenterInside

结论

希望本文能帮助改进 Android 开发。如果您有任何要添加的内容,请在此处写下并分享您的代码!

--
您真诚的,
Pavel B. Chernov

历史

  • 2010 年 12 月 14 日:初始帖子
© . All rights reserved.