Illustration af Virginia Poltrack

Brug af vektoraktiver i Android-apps

I tidligere indlæg har vi set på Android's VectorDrawable-billedformat, og hvad det kan gøre:

I dette indlæg undersøger vi, hvordan du bruger dem i dine apps. VectorDrawable blev introduceret i Lollipop (API 21) og er også tilgængelig i AndroidX (som VectorDrawableCompat), hvilket bringer support helt tilbage til API 14 (over 99% af enhederne). Dette indlæg beskriver råd om faktisk brug af VectorDrawables i dine apps.

AndroidX først

Fra Lollipop og fremefter kan du bruge VectorDrawables hvor som helst, hvor du vil bruge andre trækbare typer (henvises til dem ved hjælp af standard @ drawable / foo-syntaks), men jeg vil i stedet anbefale at altid bruge AndroidX-implementeringen. Dette øger naturligvis udvalget af platforme, du kan bruge dem på, men mere end dette muliggør det også backporting af funktioner og fejlrettelser til ældre platforme. Brug af VectorDrawableCompat fra AndroidX muliggør for eksempel:

  • Både nonZero og evenOdd path fillTypes - de to almindelige måder til at definere indersiden af ​​en form, ofte brugt i SVG'er (evenOdd tilføjet til platform impl i API 24)
  • Gradient & ColorStateList udfylder / streger (tilføjet til platform impl impl i API 24)
  • Fejlrettelser

Faktisk vil AndroidX bruge den kompatible implementering, selv på nogle platforme, hvor der findes en oprindelig implementering (i øjeblikket API'er 21-23) for at levere ovennævnte fordele. Ellers delegerer det til platformimplementeringen, så modtager stadig forbedringer på nyere udgivelser (for eksempel blev VectorDrawable geninstalleret i C i API 24 for øget ydelse).

Af disse grunde skal du altid bruge AndroidX, selvom du er heldig nok til at have en minSdkVersion på 24. Der er lidt ulemper, og hvis / når VectorDrawable udvides med nye muligheder i fremtiden, og de er også tilføjet til AndroidX, så de Jeg vil være tilgængelig med det samme uden at skulle gentage din kode igen.

Alex Lockwood får det:

Hvordan?

For at bruge AndroidX vektorsupport er der 2 ting, du skal gøre:

1. Aktivér support

Du skal tilmelde dig AndroidX vektorsupport i din app's build.gradle:

android {
    defaultConfig {
        vectorDrawables.useSupportLibrary = sandt
    }
}

Dette flag forhindrer, at Android Gradle Plugin genererer PNG-versioner af dine vektoraktiver, hvis din minSdkVersion er <21 - vi har ikke brug for dette, da vi i stedet bruger AndroidX-biblioteket.

Det overføres også til build-værktøjskæden. Som standard versioner af AAPT (Android Asset Packaging Tool) -ressourcer. Det betyder, at hvis du erklærer en VectorDrawable i res / drawable / den flytter den til res / drawable-v21 / for dig, da den ved, er det, da VectorDrawable-klassen blev introduceret.

Dette forhindrer attribut-ID-sammenstød - de attributter, du bruger i VectorDrawables (android: pathData, android: fillColor osv.) Har hver et heltal-ID tilknyttet dem, som blev tilføjet i API 21. På ældre versioner af Android var der intet, der forhindrede OEM'er fra bruger eventuelle 'ikke-krævede' ID'er, hvilket gør det usikkert at bruge en nyere attribut på en ældre platform.

Denne versionering forhindrer adgang til aktivet på ældre platforme og gør en backport umulig - gradeflagget deaktiverer denne versionering for vektortegnelige tegn. Dette er grunden til, at du bruger Android: pathData osv. Inden for dine vektorer i stedet for at skulle skifte til app: pathData osv. Som anden backported-funktionalitet.

2. Indlæs med AndroidX

Ved indlæsning af tegnestokke skal du bruge metoder fra AndroidX, der giver den bagportede vektorsupport. Indgangspunktet for dette er altid at indlæse tegnestole med AppCompatResources.getDrawable. Mens der er en række måder at indlæse tegnestave på (fordi årsager), skal du bruge AppCompatResources, hvis du vil bruge kompatible vektorer. Hvis du ikke gør dette, tilslutter du ikke AndroidX-kodestien, og din app kan muligvis gå ned, når du prøver at bruge nogen funktioner, der ikke understøttes af den platform, du kører på.

VectorDrawableCompat tilbyder også en oprettelsesmetode. Jeg vil anbefale altid at bruge AppCompatResources i stedet, da dette tilføjer et lag cache.

Hvis du ønsker at indstille tegnestativer deklarativt (dvs. i dine layouts), tilbyder appcompat et antal * Compat-attributter, som du skal bruge i stedet for standardplatformen:

ImageView, ImageButton:

  • Må ikke: android: src
  • Gør: app: srcCompat

CheckBox, RadioButton:

  • Ikke: android: -knap
  • Gør: app: buttonCompat

TextView (pr. Appcompat: 1.1.0):

  • Don’t: android: drawableStart android: drawableTop osv.
  • Gør: app: drawableStartCompat app: drawableTopCompat osv.

Da disse attributter er en del af appcompat-biblioteket, skal du huske at bruge app: namespace. Internt disse AppCompat * -visninger bruger AppCompatResources selv for at aktivere indlæsning af vektorer.

Hvis du vil forstå, hvordan appcompat udveksler TextView osv., Erklærer du for en AppCompatTextView, der aktiverer denne funktionalitet, så tjek denne artikel: https://helw.net/2018/08/06/appcompat-view-inflation/

I praksis

Disse krav påvirker den måde, du muligvis opretter et layout eller adgangsressourcer til. Her er nogle praktiske overvejelser.

Visninger uden kompatible attributter

Desværre er der et antal steder, som du måske ønsker at specificere tegnbare tegn på visninger, der ikke tilbyder kompatible attributter (f.eks. Er der ingen ubestemmeligDrawableCompat-attribut til ProgressBars), dvs. noget, der ikke er nævnt ovenfor. Det er stadig muligt at bruge AndroidX-vektorer, men du skal gøre dette fra kode:

Hvis du bruger Data Binding, kan dette udføres ved hjælp af en brugerdefineret indbindingsadapter:

Bemærk, at vi ikke ønsker, at dataindbinding skal indlæse det tegnbare for os (da det ikke bruger AppCompatResources til at indlæse tegnestol i øjeblikket), så vi kan ikke henvise til tegningen direkte som @ {@ drawable / foo}. I stedet vil vi overføre det tegnbare id til den bindende adapter, så vi er nødt til at importere R-klassen for at henvise til den:

Indlejrede tegnestokke

Nogle trækbare typer kan nestes f.eks. StateListDrawables, InsetDrawables eller LayerDrawables indeholder andre underordnede tegn. AndroidX-understøttelsen fungerer ved eksplicit at vide, hvordan man blæser op -elementer (også animerede vektorer og animerede-vælgere, men vi fokuserer på statiske vektorer i dag). Når du kalder AppCompatResources.getDrawable, peger den på ressourcen med det givne id, og hvis det er en vektor (dvs. rodelementet er ), pumpes det manuelt op for dig. Ellers overleveres den til platformen for at oppustes - når du gør det, er der ingen måde for AndroidX at genindføre sig igen i processen. Det betyder, at hvis du har en InsetDrawable, der indeholder en vektor, og beder AppCompatResources om at indlæse den for dig, vil den se -tagget, trække skulder og give den til platformen, der skal indlæses. Det får derfor ikke en chance for at indlæse den indlejrede , så dette vil enten mislykkes (på API <21) eller bare falde tilbage til platformstøtten.

For at omgå dette kan du oprette tegnestre i kode; dvs. brug AppCompatResources til at oppustere vektoren og oprette derefter tegnet InsetDrawable manuelt.

En undtagelse er en nylig tilføjelse til AndroidX (fra appcompat: 1.0.0) bagporteret AnimatedStateListDrawables. Dette er en version af StateListDrawable med animerede overgange mellem stater (i form af AnimatedVectorDrawables). Men der er intet, der kræver, at du erklærer overgange. Så hvis du bare har brug for en StateListDrawable, som kan oppustere børnevektorer ved hjælp af AndroidX, så kan du bruge denne:

Der er en måde at aktivere vektorer i indlejrede tegnestole ved hjælp af AppCompatDelegate # setCompatVectorFromResourcesEnabled, men det har et antal ulemper. Sørg for at læse javadoc omhyggeligt.

Ude af procesbelastning

Engang har du brug for at levere lodrette pladser, hvor du ikke kontrollerer hvornår eller hvordan de indlæses. For eksempel: underretninger, hjemmeskærms-widgets eller nogle aktiver, der er specificeret i dit tema (f.eks. Indstilling android: windowsBackground, der indlæses af platformen, når du opretter et eksempelvindue). I disse tilfælde er du ikke ansvarlig for indlæsning af tegnet, så der er ingen mulighed for at integrere AndroidX-support, og du kan ikke bruge vektorer før-API 21 .

Du kan naturligvis bruge vektorer på API 21+, men vær opmærksom på, at du muligvis ikke nyder de funktioner / bugfixes, der leveres af AndroidX. For eksempel er det fantastisk, at AndroidX-backports fillType = "evenOdd", en vektor, der bruger denne uden for AndroidX-support på en API 21-23-enhed, ikke forstår denne attribut. I dette specifikke eksempel vil jeg dække, hvordan jeg konverterer fillType på designtidspunktet i den næste artikel. Ellers skal du muligvis angive alternative ressourcer til forskellige API-niveauer:

res /
  trækbare-xxhdpi /
    foo.png <- raster
  trækbare-anydpi-V21 /
    foo.xml <- vektor
  trækbare-anydpi-v24 /
    foo.xml <- vektor med smarte funktioner

Bemærk, at vi skal inkludere anydpi-ressourcekvalifikatoren her ud over api-niveaukvalifikatoren. Dette skyldes den måde, hvorpå ressourcekvalificeringspræference fungerer; ethvert aktiv i trækbar - > dpi ville blive betragtet som en bedre match end et i bare drawable-v21.

X markerer stedet

Forhåbentlig har denne artikel fremhævet fordelene ved at bruge AndroidX vektorsupport og nogle begrænsninger, som du skal være opmærksom på. Brug af AndroidX-understøttelsen muliggør både vektorer på flere platformversioner og backports-funktionalitet, men indstiller dig også til at modtage eventuelle fremtidige opdateringer.

Nu hvor vi forstår både hvorfor og hvordan du skal bruge vektorer, går den næste artikel ind i, hvordan man opretter dem.

Kommer snart: Opretter vektoraktiver til Android
Kommer snart: Profilering af Android VectorDrawables