Was sind Best Practices für die Verwendung von SVG-Symbolen unter Android?

75

Ich bin dabei, meine erste native Android- App (also nicht browserbasiert) zu erstellen und suche nach bewährten Methoden zum Erstellen / Bereitstellen von Symbolen. Da es mehrere Geräte / Auflösungen unterstützen sollte, hielt ich es für am besten, SVG zu verwenden, um sie zu erstellen. Es gibt mindestens diese Bibliothek: http://code.google.com/p/svg-android/ , die verspricht, SVG auf Android zu unterstützen.

Bisher habe ich keine Ressourcen gefunden, die die Verwendung dieser oder einer anderen Bibliothek als Mittel zum Rendern von SVG-Symbolen auf dem Gerät beschreiben. Daher bin ich etwas zurückhaltend bei der Verwendung. Das Beste, was ich bisher gesehen habe, ist die Verwendung von SVG als Quellformat für das Vorrendern von PNG-basierten Symbolen in verschiedenen Auflösungen.

Meine Fragen lauten also: Sind SVG-Symbole eine gute Option, um sie direkt auf dem Gerät ohne einen PNG-Vor-Rendering-Schritt zu verwenden (funktioniert das überhaupt), und wenn, warum scheint niemand diesen Ansatz zu verwenden?

user462982
quelle

Antworten:

30

Für Android, das älter als Lollipop ist, besteht Ihre beste Vorgehensweise für SVG unter Android darin, ein Tool zu verwenden, mit dem Sie Ihr SVG in die Größe (n) konvertieren können, an der Sie interessiert sind. Die vorhandene SVG-Unterstützung für Android umfasst nicht Ihre Angaben Es ist wahrscheinlich, dass es in einer SVG-Datei gefunden wird, und selbst wenn dies der Fall wäre, ist die Unterstützung nicht in das Betriebssystem integriert, sodass eine direkte Verwendung für Symbole definitiv nicht möglich ist.

Beginnend mit Lollipop (API 21) siehe Was sind Best Practices für die Verwendung von SVG-Symbolen unter Android? . Vielen Dank an @MarkWhitaker @AustynMahoney für diesen Hinweis.

mah
quelle
1
Androidify verwendet diese Bibliothek und sie sieht ziemlich umfassend aus. Die Bibliothek scheint in der Lage zu sein, Bilder und Zeichnungen zu produzieren. Wäre es möglich, damit eine benutzerdefinierte Symbolklasse zu erstellen, die dies nutzt?
user462982
Wenn das Symbol, auf das Sie sich beziehen, im Launcher angezeigt wird, nein. In Android können Sie keine Methode zum Generieren des Symbols angeben, sondern nur das Symbol anhand seiner Ressource identifizieren.
Mah
1
Wenn die Bibliothek, mit der Sie arbeiten, die SVGs, die Sie haben, gut verarbeiten kann, können Sie sie für Schaltflächen verwenden, jedoch nicht über die Standard-Android-API. Sie müssen eine benutzerdefinierte Schaltflächenansicht erstellen. Vor ungefähr 12 bis 18 Monaten habe ich die von Ihnen verlinkte Bibliothek verwendet und zu diesem Zeitpunkt hatte sie Probleme mit vielen SVGs, die ich in Inkscape erstellt oder von verschiedenen Stellen heruntergeladen hatte. Vielleicht hat sich die Unterstützung seitdem verbessert, aber ich empfehle, sie mit den genauen SVGs zu testen, die Sie verwenden möchten, bevor Sie viel benutzerdefinierten Code dafür schreiben.
Mah
2
Diese Antwort ist jetzt definitiv nicht richtig. stackoverflow.com/a/29229005/116938
Austyn Mahoney
1
veraltete Antwort
Bendaf
46

Ab Lollipop (API 21) definiert Android die VectorDrawable- Klasse zum Definieren von Drawables basierend auf Vektorgrafiken. Android Studio 1.4 fügt das "Vector Asset Studio" hinzu , um die Arbeit zu vereinfachen, einschließlich einer SVG-Importfunktion und eines neuen Gradle-Plugins, das PNG-Versionen von VectorDrawable-Symbolen zur Erstellungszeit für API 20 und früher generiert. Es gibt auch ein Drittanbieter-Tool zum Konvertieren von SVGs in VectorDrawables . Beachten Sie, dass Vektorzeichnungen zwar in XML definiert werden können, das Dateiformat jedoch nicht SVG ist und nicht alle SVG-Dateien erfolgreich konvertiert werden können. Einfache Grafiken wie Symbole sollten in Ordnung sein.

Wenn Sie dennoch selbst PNGs generieren müssen, müssen Sie Ihre Symbole in verschiedenen Auflösungen generieren . Um das Generieren dieser PNGs zu vereinfachen, entwerfe ich Symbole als SVG und exportiere sie dann mit Inkscape, das kostenlos und plattformübergreifend ist, in die verschiedenen Größen . Es verfügt über einige nützliche Funktionen zum Entwerfen von Symbolen, einschließlich der Symbolvorschau (siehe unten), und generiert schöne, gestochen scharfe PNGs.

Geben Sie hier die Bildbeschreibung ein

Mark Whitaker
quelle
2
Leider ist die SVG-Importfunktion sehr, sehr einfach.
Robin
2
Das Android-Team hat die Abwärtskompatibilitätsunterstützung für Vector Assets in Android Studio 1.4 veröffentlicht. Ich habe die Antwort aktualisiert, um dies widerzuspiegeln. android-developers.blogspot.com/2015/09/android-studio-14.html
Austyn Mahoney
Tutorial Link fehlt / führt zu dieser Seite
V-Master
31

Dies ist, was wir verwenden, um eine SVG-Datei in mehrere Auflösungen umzuwandeln. So generieren Sie beispielsweise das Startsymbol: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
Nacho Coloma
quelle
Gut zu wissen, schönes Skript, sehr nützlich. Ich kann vermeiden, SVGs in GIMP oder PS zu importieren. Ich denke, Sie sollten einige Tipps zur Verwendung hinzufügen (es schlägt fehl, wenn die Ordner nicht vorhanden sind).
JC
16

Gute Nachrichten, Leute! Seit der Android Support Library 23.2 können wir svg-s bis zurück zu API Level 7 verwenden !

Wenn Sie nur bis Lollipop (API 21) abwärtskompatibel sein möchten, überprüfen Sie Mark Whitakers Antwort. Wenn Sie jedoch nach unten gehen möchten, müssen Sie diese Zeilen zu Ihrem build.gradle hinzufügen:

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

Denken Sie auch daran, dass:

  • Stattdessen müssen android:srcSie das app:srcCompatAttribut in ImageViews verwenden.
  • Sie können svg-s nicht in StateListDrawables oder anderen XML-Drawables verwenden. Erstellen Sie sie stattdessen programmgesteuert.
  • Sie können das android:backgroundAttribut oder die View.setBackgroundResource()Funktion nicht verwenden , View.setBackground()sondern stattdessen.
  • Sie können svg-s bei Benachrichtigungen nicht verwenden.
Bendaf
quelle
Ich habe dies getan, aber ich sehe die SVG nur auf Geräten mit API-Level> 21. Was ist hier falsch?
Morteza Rastgoo
1
Verwenden Sie Farbattribute in Ihrem SVG? Könnten Sie eine neue Frage erstellen und dort das SVG und Ihre build.gradle-Datei einfügen?
Bendaf
1
@ Morteza überprüfen Sie diese Antwort auch, wenn es bei Ihnen immer noch nicht funktioniert: stackoverflow.com/a/36661438/3162918
Bendaf
8

Da mir die Antwort von Nacho-Coloma geholfen hat, habe ich sein ausgezeichnetes Skript genommen und es etwas einfacher gemacht, es täglich zu verwenden.

Zuerst:

  1. Erstellen Sie ein Verzeichnis drawable-svgneben Ihrem resVerzeichnis.
  2. Platzieren Sie Ihre SVG-Dateien und dieses Skript in drawable-svg.
  3. Machen Sie das Skript ausführbar.
  4. Starte es. In Ubuntu können Sie einfach in Nautilus darauf doppelklicken und es in einem Terminal ausführen.

Und später, wenn Sie neue SVG-Dateien erhalten:

  1. Legen Sie neue SVG-Dateien ab drawable-svgund führen Sie das Skript erneut aus.

Standardmäßig wird es tun , was Sie wollen: Skalieren jede svg - Datei in PNG - Dateien und steckt sie in ../res/drawable-mdpi, ../res/drawable-hdpiusw.

Das Skript akzeptiert zwei Parameter:

  1. Das zu skalierende SVG-Dateimuster, Standard: *.svg
  2. Das Basisverzeichnis für put, Standard ../res/(dh Ihr resVerzeichnis mit dem oben genannten Setup).

Sie können experimentieren, indem Sie eine einzelne SVG-Datei im aktuellen Verzeichnis wie folgt in PNGs skalieren:

$ ./svg2png test.svg .

Oder verarbeiten Sie einfach alle Bilder:

$ ./svg2png

Ich denke, Sie könnten das drawable-svgin das res-Verzeichnis einfügen, aber ich habe nicht untersucht, was in der endgültigen APK verpackt wird. Außerdem haben meine SVG-Dateien -Namen, die Android nicht mag, und mein Skript kümmert sich darum, die PNG-Dateien in etwas umzubenennen, das unter Android gültig ist.

Ich verwende ImageMagick für die Konvertierung, die etwas standardmäßiger ist als Inkscape (obwohl mir der Ansatz gefallen hat). Beide Methoden sind als Referenz im Skript enthalten.

Hier ist das Skript:

#!/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.
Stephan Henningsen
quelle
5

Android Support Library 23.2 Unterstützt Vector Drawables und Animated Vector Drawables

  1. fügen Sie vectorDrawables.useSupportLibrary = truein Ihre build.gradle Datei.
  2. Verwenden Sie app:srcCompat="@drawable/ic_add"anstelle von android:src="..."oder setImageResource()für Ihre ImageView

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

Lordmegamax
quelle
Ich habe dies getan, aber ich sehe die SVG nur auf Geräten mit API-Level> 21. Was ist hier falsch?
Morteza Rastgoo
@MortezaRastgoo Könnten Sie bitte Ihren Code irgendwo zeigen? Ich kann es nicht erraten. Es funktioniert gut für mich.
Lordmegamax
3

SVG-Symbole sind keine gute Option, um sie direkt auf einem Gerät zu verwenden, wenn sie auf viele verschiedene Größen skaliert werden müssen. Daher möchten Sie normalerweise zunächst das Vektorformat verwenden. Ein großes Symbol wird niemals elegant verkleinert, da Computerbildschirme aus Pixeln bestehen. So können die Linien des Vektorbildes "zwischen Pixeln" ausgerichtet werden, wodurch ein verschwommener Rand entsteht. Darüber hinaus benötigen große Symbole mehr Details als kleine Symbole, für die nur sehr wenige Details erforderlich sind. Ein detailliertes Symbol sieht in sehr kleinen Größen nicht gut aus, und ein einfaches Symbol sieht in großen Größen nicht gut aus. Ich habe kürzlich einen ausgezeichneten Artikel eines professionellen UI-Designers darüber gelesen: Über diese Vektorsymbole .

Null eins
quelle
Sie können diese Dinge bis zu einem gewissen Grad mit steuern shape-rendering. Die Unterstützung ist jedoch spärlich.
Joey
Danke @Joey, das ist gut zu wissen. Selbst dann können Sie nicht festlegen, dass ein Element vollständig gelöscht werden soll, wenn das Bild so klein gerendert wird.
ZeroOne
4
Zufällige Sache, an die ich gerade gedacht habe: Die unterschiedlichen Symbolgrößen in Apps sind normalerweise auf unterschiedliche Pixeldichten des Zielgeräts zurückzuführen - daher erscheinen alle ungefähr auf derselben visuellen Größe. So sie eigentlich nicht braucht mehr oder weniger abhängig von der Größe detailliert sein. Zumindest nicht in diesem Zusammenhang. Ich verwende derzeit SVG als Quellformat für Symbole in zwei Android-Apps bei der Arbeit und das einzige, was Sie möglicherweise achten müssen, ist das Ausrichten von Kanten an Pixelgrenzen für die Grundliniengröße (mdpi). Android schlägt außerdem vor, dass Symbole mindestens zwei Pixel für Linien mit Grundliniengröße verwenden.
Joey
1
Ich verwende Inkscape, um sie in den erforderlichen Auflösungen zu rendern. Da unser Künstler sowieso Vektorsymbole zeichnet, ist dies der einfachste Ansatz. Es ermöglicht auch das sofortige Generieren von Farbverläufen von Opazitätsvariationen (z. B. aktivierte / deaktivierte Symbolpaare), was ein großer Vorteil von SVG ist. Der Unterschied beim Herunterskalieren des größten PNG ist gering, aber subtil sichtbar (die Kanten sind nicht ganz so scharf, da Sie auch das Antialiasing verkleinern).
Joey
1
Sie benötigen nur eine Version für besonders niedrige Auflösungen und eine für alle anderen. vs was, 5-6 verschiedene Bitmaps müssen Sie gerade für Android bereitstellen? Warum sollten Sie die unterstützten Bildformate einschränken? Lassen Sie den Benutzer entscheiden, welches Format er bevorzugt.
Velis
2

Ich habe gerade ein Skript zum Generieren aller Plattformsymbole für PhoneGap-Apps veröffentlicht, die möglicherweise von Wert sind. Noch Code zum Generieren von Bildschirmen hinzufügen.

Tony O'Hagan
quelle
2

Ich habe gerade angefangen, Victor zu benutzen , eine Open-Source-Bibliothek von Trello, zu verwenden, um SVG-Dateien während der Erstellungszeit in PNG-Dateien mit den verschiedenen erforderlichen Auflösungen zu konvertieren.

PROS

  • Sie müssen nicht jedes Mal ein Skript oder Tool ausführen, um verschiedene PNG-Dateien zu erstellen, wenn Sie ein Symbol ändern oder hinzufügen. (Sie müssen in Android Studio auf Neu erstellen klicken, wenn Sie eine neue SVG-Datei hinzugefügt oder eine vorhandene umbenannt haben.)
  • In Ihrer Quelle befinden sich keine PNGs, sodass weniger Unordnung entsteht.

Nachteile

  • Der einzige Nachteil, den ich bisher gesehen habe, ist, dass Android Studio generierte Ressourcen in XML noch nicht erkennt. Daher werden in Ihren XML-Dateien einige rote Warnungen angezeigt, und Sie haben keine automatische Vervollständigung für Ihre SVG-basierten Drawables. Es funktioniert jedoch einwandfrei und dieses Problem sollte in einer zukünftigen Version von Android Studio behoben werden.

Wenn Sie SVG verwenden, das von http://materialdesignicons.com/ generiert wurde, müssen Sie entweder die gesamte Datei herunterladen oder von der Registerkarte "SVG-Datei" kopieren, wenn Sie "SVG anzeigen" auswählen.

Ciske Boekelo
quelle
1

svg ist großartig. wer möchte svg verwenden:

Klicken Sie mit der rechten Maustaste auf "Neu / Vector Asset" und wählen Sie "Materialsymbol" für Standardsymbole und "Gebietsschema-SVG-Datei" für Ihre Datei auf Ihrer Computerfestplatte. Geben Sie unter "Ressourcenname" den Namen für die SVG-Datei ein und klicken Sie dann auf "Weiter" und beende"

und Sie können das in zeichnbar verwenden. Füllfarbe muss harter Code sein.

einfaches Beispiel

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>
mehrdad khosravi
quelle
0

Ich hatte noch nie viel Glück beim Ausführen von Linux-Shell-Skripten in Cygwin unter Windows. Hier ist also eine Batch-Datei, die genau das tut, was Nacho Colomas Bash-Skript tut. Ein kleiner Unterschied besteht darin, dass diese Batchdatei sowohl einen Eingabe- als auch einen Ausgabedateinamen erfordert, wie in "svg2png -w24 input.svg output.png".

Richten Sie einen "svg" -Ordner im src / main-Verzeichnis Ihres Projekts ein und kopieren Sie Ihre SVG-Dateien und diese Batch-Datei gemäß Stephans Anweisungen in diesen Ordner. Führen Sie die Batchdatei aus dem Ordner svg aus. Wenn Sie unter 32-Bit-Windows arbeiten, müssen Sie wahrscheinlich den Pfad zu Inkscape ändern, um "Programme (x86)" zu verwenden.

@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
Linda X.
quelle