ChatGPT解决这个技术问题 Extra ChatGPT

在 Android 上使用 SVG 图标的最佳做法是什么?

我即将创建我的第一个 Android native(因此不是基于浏览器的)应用程序,并寻找一些有关图标创建/配置的良好做法。由于它应该支持多种设备/分辨率,我认为最好使用 SVG 来创建它们。至少有这个 lib: http://code.google.com/p/svg-android/ 承诺在 Android 上提供对 SVG 的支持。

到目前为止,我还没有找到描述使用这个或另一个库作为在设备上呈现 SVG 图标的方法的资源,所以我有点不愿意使用它。到目前为止,我看到的最好的方法是使用 SVG 作为源格式,以不同分辨率预渲染基于 png 的图标。

所以我的问题是:SVG 图标是否是直接在设备上使用而无需 png 预渲染步骤的好选择(它是否有效),如果,为什么似乎没有人使用这种方法?


M
Mark Whitaker

从 Lollipop (API 21) 开始,Android 定义了 VectorDrawable 类,用于定义基于矢量图形的可绘制对象。 Android Studio 1.4 adds the "Vector Asset Studio" 使它们更易于使用,包括 SVG 导入功能和新的 Gradle 插件,该插件可在 API 20 及更早版本的构建时生成 PNG 版本的 VectorDrawable 图标。还有a third-party tool for converting SVGs to VectorDrawables。请记住,虽然矢量可绘制对象可以在 XML 中定义,但文件格式不是 SVG,并且并非所有 SVG 文件都可以成功转换。像图标这样的简单图形应该可以正常工作。

如果您仍需要自己生成 PNG,则需要生成图标 at various resolutions。为了便于生成这些 PNG,我将图标设计为 SVG,然后使用免费且跨平台的 Inkscape 导出为各种尺寸。它有一些很好的图标设计功能,包括图标预览视图(见下文),它可以生成漂亮的清晰 PNG。

https://i.stack.imgur.com/epHOv.png


不幸的是,SVG 导入功能非常非常基础。
Android 团队在 Android Studio 1.4 中发布了对 Vector Assets 的向后兼容性支持。我已经更新了答案以反映这一点。 android-developers.blogspot.com/2015/09/android-studio-14.html
教程链接丢失/指向此页面
C
Community

对于比 Lollipop 更早的 Android,您在 Android 上使用 SVG 的最佳实践是使用一种工具将您的 SVG 转换为您感兴趣的尺寸的 PNG。现有的 SVG 对 Android 的支持并不全面' 可能会在 SVG 文件中找到,即使是这样,操作系统也没有内置支持,因此直接将它们用于图标肯定是不可用的。

从 Lollipop (API 21) 开始,请参阅 What are best practices for using SVG icons on Android?。感谢@MarkWhitaker @AustynMahoney 指出这一点。


Androidify 使用了这个库,看起来相当全面。该库似乎能够生成图片和可绘制对象。是否可以使用它来创建一个利用它的自定义图标类?
如果您所指的图标是启动器中显示的图标,则不会。 Android 不允许您指定生成图标的方法,它只允许您通过其资源来识别图标。
如果您正在使用的库可以很好地处理您拥有的 SVG,您可以使其适用于按钮,但不能通过标准的 Android API;您需要创建一个自定义按钮视图。大约 12 到 18 个月前,我使用了您链接的库,当时它无法处理我在 Inkscape 中创建或从各个地方下载的许多 SVG。也许从那时起它的支持有所改进,但我建议在为它编写大量自定义代码之前使用您计划使用的确切 SVG 对其进行测试。
这个答案现在肯定是不正确的。 stackoverflow.com/a/29229005/116938
过时的答案
N
Nacho Coloma

这就是我们用来将 SVG 文件转换为多种分辨率的方法。例如,要生成启动图标:svg2png -w48 icon.svg

#!/bin/bash -e
# Transforms a SVG into a PNG for each platform
# Sizes extracted from
# http://developer.android.com/design/style/iconography.html

[ -z $2 ] && echo -e "ERROR: filename and one dimension (-w or -h) is required, for example:\nsvg2png -w48 icon.svg\n" && exit 1;
FILENAME=$2
DEST_FILENAME=`echo $2 | sed s/\.svg/\.png/`
FLAG=`echo $1 | cut -c1-2`
ORIGINAL_VALUE=`echo $1 | cut -c3-`

if [ "$FLAG" != "-w" ] && [ "$FLAG" != "-h" ]; then
    echo "Unknown parameter: $FLAG" 
    exit 1
fi

# PARAMETERS: {multiplier} {destination folder}
function export {
  VALUE=$(echo "scale=0; $ORIGINAL_VALUE*$1" | bc -l)
  CMD="inkscape $FLAG$VALUE --export-background-opacity=0 --export-png=src/main/res/$2/$DEST_FILENAME src/main/svg/$FILENAME > /dev/null"
  echo $CMD
  eval $CMD
} 

export 1 drawable-mdpi
export 1.5 drawable-hdpi
export 2 drawable-xhdpi
export 3 drawable-xxhdpi
export 4 drawable-xxxhdpi

很高兴知道,很好的脚本,非常有用。我可以避免将 SVG 导入 GIMP 或 PS。我认为您应该添加一些有关如何使用它的提示(如果文件夹不存在,则会失败)。
C
Community

大家好消息!由于 android 支持 library 23.2,我们可以使用 svg-s 直到回到 API 级别 7

如果您只想在 Lollipop (API 21) 之前向后兼容,请检查 Mark Whitaker's 答案,但如果您想低于您需要将这些行添加到您的 build.gradle:

// Gradle Plugin 2.0+ (if you using older version check the library announcement link)
android {  
    defaultConfig {  
        vectorDrawables.useSupportLibrary = true  
    }  
}  

另请记住:

而不是 android:src 你需要在 ImageViews 中使用 app:srcCompat 属性。

您不能在 StateListDrawables 或其他 xml drawables 中使用 svg-s,而是以编程方式创建它们。

您不能使用 android:background 属性或 View.setBackgroundResource() 函数,而是使用 View.setBackground() 。

在通知的情况下,您不能使用 svg-s。


我已经这样做了,但我只在 api 级别 > 21 的设备上看到 svg。这里有什么问题?
您是否在 svg 中使用颜色属性?您可以创建一个新问题并在其中插入 svg 和 build.gradle 文件吗?
@Morteza 也检查这个答案,如果它仍然对你不起作用:stackoverflow.com/a/36661438/3162918
S
Stephan Henningsen

由于 nacho-coloma 的回答对我有所帮助,因此我采用了他出色的脚本并使其在日常使用中变得更容易一些。

第一的:

在 res 目录旁边创建目录 drawable-svg。将您的 svg 文件和此脚本放在 drawable-svg 中。使脚本可执行。运行。在 Ubuntu 中,您只需在 Nautilus 中双击它并使其在终端中运行。

稍后当您获得新的 svg 文件时:

将新的 svg 文件放入 drawable-svg 并再次运行脚本。

默认情况下,它会做你想做的事:将每个 svg 文件缩放为 png 文件并将它们放入 ../res/drawable-mdpi../res/drawable-hdpi 等。

该脚本有两个参数:

要缩放的 svg 文件模式,默认值:*.svg put 的基本目录,默认值 ../res/(即具有上述设置的 res 目录)。

您可以通过将单个 svg 缩放为当前目录中的 png 来进行实验,如下所示:

$ ./svg2png test.svg .

或者简单地处理所有图像:

$ ./svg2png

我想您可以将 drawable-svg 放在 res 目录中,但我还没有研究最终 APK 中包含的内容。此外,我的 svg 文件的名称中有 -,这是 Android 不喜欢的,我的脚本负责将 png 文件重命名为在 Android 上有效的名称。

我正在使用 ImageMagick 进行转换,它比 Inkscape 更标准(尽管我喜欢这种方法)。这两种方法都包含在脚本中以供参考。

这是脚本:

#!/bin/bash

scalesvg ()
{
    svgfile="$1"
    pngdir="$2"
    pngscale="$3"
    qualifier="$4"

    svgwidthxheight=$(identify "$svgfile" | cut -d ' ' -f 3)
    svgwidth=${svgwidthxheight%x*}
    svgheight=${svgwidthxheight#*x}

    pngfile="$(basename $svgfile)" # Strip path.
    pngfile="${pngfile/.svg/.png}" # Replace extension.
    pngfile="${pngfile/[^A-Za-z0-9._]/_}" # Replace invalid characters.
    pngfile="$pngdir/$qualifier/$pngfile" # Prepend output path.

    if [ ! -d $(dirname "$pngfile") ]; then
        echo "WARNING: Output directory does not exist: $(dirname "$pngfile")"
        #echo "Exiting"
        #exit 1
        echo "Outputting here instead: $pngfile"
        pngfile="$qualifier-${svgfile/.svg/.png}"
    fi

    pngwidth=$(echo "scale=0; $svgwidth*$pngscale" | bc -l)
    pngheight=$(echo "scale=0; $svgheight*$pngscale" | bc -l)
    pngdensity=$(echo "scale=0; 72*$pngscale" | bc -l) # 72 is default, 

    echo "$svgfile ${svgwidth}×${svgheight}px -> $pngfile ${pngwidth}×${pngheight}px @ $pngdensity dpi"

    convert -background transparent -density $pngdensity "$svgfile" "$pngfile"
    #inkscape -w${pngwidth} --export-background-opacity=0 --export-png="$pngfile" "$svgfile" > /dev/null
    #convert "$svgfile" -background transparent -scale ${pngwidth}x${pngheight} "$pngfile"
}



svgfiles="$1"
svgfiles="${svgfiles:=*.svg}" # Default to input all *.svg in current dir.

pngdir="$2"
pngdir="${pngdir:=../res}" # Default to place output pngs to ../res, ie. ../res/drawable-hdpi etc.

for svgfile in $svgfiles; do
    echo "Scaling $svgfile ..."
    scalesvg "$svgfile" "$pngdir" 0.75 drawable-ldpi
    scalesvg "$svgfile" "$pngdir" 1    drawable-mdpi
    scalesvg "$svgfile" "$pngdir" 1.5  drawable-hdpi
    scalesvg "$svgfile" "$pngdir" 2    drawable-xhdpi
    scalesvg "$svgfile" "$pngdir" 3    drawable-xxhdpi
    scalesvg "$svgfile" "$pngdir" 4    drawable-xxxhdpi
done

echo -n "Done."
read # I've made it wait for Enter -- convenient when run from Nautilus.

E
Endless

另一种选择是将您的 SVG 资源转换为 TTF 字体类型。在您的应用程序中包含字体并以这种方式使用它。这可以解决单色简单形状的问题。

有几种免费的转换工具。

http://fontastic.me

https://onlinefontconverter.com

http://www.freefontconverter.com


l
lordmegamax

Android 支持库 23.2 支持 Vector Drawable 和 Animated Vector Drawable

将 vectorDrawables.useSupportLibrary = true 添加到您的 build.gradle 文件中。为您的 ImageView 使用 app:srcCompat="@drawable/ic_add" 而不是 android:src="..." 或 setImageResource()

http://android-developers.blogspot.sk/2016/02/android-support-library-232.html


我已经这样做了,但我只在 api 级别 > 21 的设备上看到 svg。这里有什么问题?
@MortezaRastgoo 您能在某处显示您的代码吗?没有它我无法猜测。这对我来说很有用。
Z
ZeroOne

如果需要将 SVG 图标缩放到许多不同的大小,那么直接在设备上使用 SVG 图标不是一个好选择,这通常是您首先要使用矢量格式的原因。大图标永远不会优雅地缩小,因为计算机显示器是由像素组成的。因此,矢量图像的线条可能会“在像素之间”对齐,从而产生模糊的边界。此外,大图标比小图标需要更多的细节,小图标需要的细节很少。一个详细的图标在非常小的尺寸下看起来不太好,一个简单的图标在放大到非常大的尺寸时看起来不太好。我最近阅读了一位专业 UI 设计师撰写的一篇出色的文章:About those vector icons


您可以使用 shape-rendering 在一定程度上控制这些事情。不过,支持很少。
谢谢@Joey,很高兴知道。但是,即使这样也不允许您指定如果图像被渲染得足够小,则应该完全删除一个元素。
我刚刚想到的随机事情:应用程序中不同的图标大小通常是由于目标设备的不同像素密度 - 因此它们都以大致相同的视觉大小出现。因此,它们实际上不需要根据大小或多或少地详细说明。至少在这种情况下不是。我目前在工作中使用 SVG 作为两个 Android 应用程序中图标的源格式,您可能需要注意的唯一一件事是将边缘与基线大小 (mdpi) 的像素边界对齐。 Android 还建议图标使用至少两个像素来表示基线大小的线条。
我正在使用 Inkscape 以必要的分辨率渲染它们;因为我们的艺术家无论如何都会绘制矢量图标,这是最简单的方法。它还允许动态生成不透明度变化的颜色(例如启用/禁用图标对),这是 SVG 的巨大优势。缩小最大 PNG 时的差异很小,但很明显(边缘不是很清晰,因为您也在缩小抗锯齿)。
对于超低分辨率,您只需要一个版本,而对于所有其他版本,您只需要一个版本。与什么相比,您现在必须为 Android 提供 5-6 个不同的位图?此外,为什么要限制支持的图像格式:让用户决定他们喜欢哪种格式。
T
Tony O'Hagan

我刚刚发布了一个脚本,用于为可能有价值的 PhoneGap 应用程序生成所有平台图标。尚未添加用于生成屏幕的代码。

https://github.com/tohagan/phonegap-graphics


C
Ciske

我刚刚开始使用 Trello 的开源库 Victor,在构建期间将 SVG 文件转换为各种所需分辨率的 PNG 文件。

优点

每次更改或添加图标时,您都不必运行脚本或工具来创建各种 PNG 文件。 (当您添加新的 svg 文件或重命名现有文件时,您确实需要在 Android Studio 中点击 Rebuild)

您的源代码中没有 PNG,因此杂乱无章。

缺点

到目前为止,我看到的唯一缺点是 Android Studio 还不能识别 XML 中生成的资源,因此您会在 XML 文件中收到一些红色警告,并且您的基于 SVG 的可绘制对象没有自动完成功能。虽然它构建得很好,并且这个问题应该在 Android Studio 的未来版本中得到解决。

如果您使用由 http://materialdesignicons.com/ 生成的 SVG,请务必下载整个文件,或者在选择“查看 SVG”时从“SVG 文件”标签复制


m
mehrdad khosravi

svg 太棒了。谁想使用 svg:

右键单击可绘制的“新/矢量资产”为默认图标选择“材质图标”,为您的计算机硬盘驱动器中的文件选择“区域设置 SVG 文件”,并在“资源名称”中输入 svg 文件的名称,然后单击“下一步”按钮和“完成”

你可以在drawable中使用它。 fillcolor 必须是硬编码。

简单的例子

导航切换.xml

<vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="24dp"
        android:height="24dp"
        android:viewportWidth="24.0"
        android:viewportHeight="24.0">
    <path
        android:fillColor="#FFFFFF"
        android:pathData="M3,18h18v-2H3v2zm0,-5h18v-2H3v2zm0,-7v2h18V6H3z"/>
</vector>

L
Linda X

我从来没有在 Windows 上的 Cygwin 中运行 Linux shell 脚本的运气。所以这里有一个批处理文件,它执行 Nacho Coloma 的 bash 脚本所做的事情。一个小的区别是,这个批处理文件需要输入和输出文件名,如“svg2png -w24 input.svg output.png”。

根据 Stephan 的说明,在项目的 src/main 目录中设置一个“svg”文件夹,并将 SVG 文件和该批处理文件复制到该文件夹中。从 svg 文件夹运行批处理文件。如果您使用的是 32 位 Windows,那么您可能需要更改 Inkscape 的路径以使用“Program Files (x86)”。

@echo off
echo Convert an SVG file to a PNG resource file with multiple resolutions.

rem Check the arguments
set temp=%1
set switch=%temp:~0,2%
set pixels=%temp:~2%
if not "%switch%"=="-w" (
if not "%switch%"=="-h" (
echo Error:  Invalid image width or height switch.  Use -w or -h, with target image size in dp appended.
goto :error
))
echo %pixels%| findstr /r /c:"^[1-9][0-9]*$" >nul
if errorlevel 1 (
echo Error:  Invalid numeric image size.  Image size must be a positive integer.
goto :error
)
if "%3"=="" (
echo Error:  Not enough arguments.
goto :error
)
if not "%4"=="" (
echo Error:  Too many arguments.
goto :error
)

call :export %1 %2 %3 mdpi
call :export %1 %2 %3 hdpi
call :export %1 %2 %3 xhdpi
call :export %1 %2 %3 xxhdpi
call :export %1 %2 %3 xxxhdpi
exit /b

:export
rem parameters: <width/height> <input-file> <output-file> <density>

set temp=%1
set switch=%temp:~0,2%
set pixels=%temp:~2%

if %4==mdpi set /a size=%pixels%
if %4==hdpi set /a size=%pixels%*3/2
if %4==xhdpi set /a size=%pixels%*2
if %4==xxhdpi set /a size=%pixels%*3
if %4==xxxhdpi set /a size=%pixels%*4

echo %size% pixels ../res/drawable-%4/%3
"C:\Program Files\Inkscape\inkscape.exe" %switch%%size% --export-background-opacity=0 --export-png=../res/drawable-%4/%3 %2
exit /b

:error
echo Synopsis: svg2png -w^<width-pixels^>^|-h^<height-pixels^> ^<input-file^> ^<output-file^>
echo Example:  svg2png -w24 "wifi white.svg" wifi_connect_24dp.png
exit /b