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

时间:2012-03-10 15:50:42

标签: android svg icons

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

到目前为止,我还没有找到描述使用此库或其他库的资源作为在设备上呈现SVG图标的方法,所以我有点不愿意使用它。到目前为止,我见过的最好的是使用SVG作为预渲染基于png的图标的源格式。

所以我的问题是:SVG图标是不是在没有png预渲染步骤的情况下直接在设备上使用的好选项(它是否可以工作),如果,为什么似乎没有人使用这种方法?

12 个答案:

答案 0 :(得分:42)

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

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

enter image description here

答案 1 :(得分:31)

这是我们用来将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

答案 2 :(得分:26)

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

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

答案 3 :(得分:15)

大家好消息!由于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。

答案 4 :(得分:8)

由于 nacho-coloma 的回答对我有所帮助,我采用了他出色的剧本,使其每天使用起来更容易。

首先:

  1. drawable-svg目录旁边创建目录res
  2. 将您的svg文件和此脚本放在drawable-svg
  3. 使脚本可执行。
  4. 运行它。在Ubuntu中,您只需在Nautilus中双击它并使其在终端中运行。
  5. 稍后当你获得新的svg文件时:

    1. 将新的svg文件放入drawable-svg并再次运行脚本。
    2. 默认情况下,它会执行您想要的操作:将每个svg文件扩展为png文件并将其放入../res/drawable-mdpi../res/drawable-hdpi等。

      该脚本有两个参数:

      1. 要扩展的svg文件模式,默认值为:*.svg
      2. put的基本目录,默认../res/(即具有上述设置的res目录)。
      3. 您可以通过将单个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.
        

答案 5 :(得分:6)

另一种选择是将SVG资产转换为TTF字体类型。在您的应用中包含该字体并以这种方式使用它。这就是单色简单形状的技巧。

有几种免费的转换工具。

答案 6 :(得分:5)

Android支持库23.2 支持矢量Drawables和动画矢量Drawables

  1. vectorDrawables.useSupportLibrary = true添加到build.gradle文件中。
  2. 使用app:srcCompat="@drawable/ic_add"代替android:src="..."setImageResource()进行ImageView
  3. http://android-developers.blogspot.sk/2016/02/android-support-library-232.html

答案 7 :(得分:3)

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

答案 8 :(得分:2)

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

答案 9 :(得分:2)

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

赞成

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

CONS

  • 到目前为止我唯一看到的缺点是Android Studio尚未识别XML中生成的资源,因此您的XML文件中会出现一些红色警告,并且您没有基于SVG的drawables的自动完成功能。它构建得很好,这个问题应该在Android Studio的未来版本中修复。

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

答案 10 :(得分:0)

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

在项目的src / main目录中设置“svg”文件夹,并根据Stephan的说明将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

答案 11 :(得分:0)

svg太棒了。 谁想要使用svg:

右键单击drawable“new / Vector Asset”,为您的计算机硬盘驱动器中的文件选择“material icon”作为默认图标和“locale SVG file”,然后在svg文件的“resource name”类型名称中选择,然后单击“下一个“按钮和”完成“

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

简单的例子

navigation_toggle.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>