【问题标题】:What are best practices for using SVG icons on Android?在 Android 上使用 SVG 图标的最佳做法是什么?
【发布时间】:2012-03-27 17:07:15
【问题描述】:

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

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

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

【问题讨论】:

    标签: android svg icons


    【解决方案1】:

    从 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。

    【讨论】:

    【解决方案2】:

    对于比 Lollipop 更早的 Android,您在 Android 上使用 SVG 的最佳做法是使用一种工具将您的 SVG 转换为您感兴趣的大小的 PNG。对 Android 的现有 SVG 支持并不全面您可能会在 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
    • 过时的答案
    【解决方案3】:

    这是我们用来将 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。我认为你应该添加一些关于如何使用它的提示(如果文件夹不存在,它会失败)。
    【解决方案4】:

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

    还要记住:

    • 您需要在 ImageViews 中使用 app:srcCompat 属性,而不是 android:src
    • 您不能在 StateListDrawables 或其他 xml 可绘制对象中使用 svg-s,而是以编程方式创建它们。
    • 您不能使用android:background 属性或View.setBackgroundResource() 函数,请改用View.setBackground()
    • 您不能在通知的情况下使用 svg-s。

    【讨论】:

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

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

    第一:

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

    然后当你得到新的 svg 文件时:

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

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

    脚本有两个参数:

    1. 要缩放的svg文件模式,默认:*.svg
    2. 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.
    

    【讨论】:

      【解决方案6】:

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

      有几种免费的转换工具。

      【讨论】:

        【解决方案7】:

        Android 支持库 23.2 支持矢量绘图和动画矢量绘图

        1. vectorDrawables.useSupportLibrary = true 添加到您的 build.gradle 文件中。
        2. 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 你能在某处显示你的代码吗?没有它我无法猜测。它对我很有效。
        【解决方案8】:

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

        【讨论】:

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

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

        【讨论】:

          【解决方案10】:

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

          优点

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

          缺点

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

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

          【讨论】:

            【解决方案11】:

            svg 很棒。 谁想使用svg:

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

            你可以在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>
            

            【讨论】:

              【解决方案12】:

              我从来没有在 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
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-03-01
                • 1970-01-01
                • 2015-01-09
                • 1970-01-01
                • 2014-11-15
                • 1970-01-01
                • 1970-01-01
                • 2021-06-19
                相关资源
                最近更新 更多