Illustration af Virginia Poltrack

Hvad er din tekst?

Forståelse af, hvordan man erklærende stil tekst på Android.

Når du styler tekst i Android-apps, tilbyder TextView flere attributter og forskellige måder at anvende dem på. Du kan indstille attributter direkte i dit layout, du kan anvende en stil på en visning eller et tema på et layout eller måske indstille et tekstudseende. Men hvilken skal du bruge? Hvad sker der, hvis du kombinerer dem?

Hvilken skal jeg bruge, og hvornår?

Denne artikel skitserer de forskellige tilgange til deklarativt styling af tekst (dvs. når du oppustes et XML-layout), ser på deres omfang og forrang, og hvornår du skal bruge hver teknik.

tl; dr;

Du skal virkelig læse hele indlægget, men her er et resume.

Vær opmærksom på rækkefølgen af ​​forskellige stylingteknikker - hvis du prøver at style en eller anden tekst og ikke ser de resultater, du forventer, bliver dine ændringer sandsynligvis tilsidesat af noget højere oppe i dette hierarki:

Hierarkiet af tekststylingsteknikker

Jeg vil foreslå denne arbejdsgang til stylingstekst:

  1. Indstil en app-bred styling i en textViewStyle-standardstil i dit tema.
  2. Konfigurer et (lille) udvalg af TextAppearances, som din app bruger (eller bruger / udvider fra MaterialComponents stilarter) og henviser disse direkte fra dine synspunkter
  3. Opret stilarter, der indstiller alle attributter, der ikke understøttes af TextAppearance (som selv specificerer en af ​​dine TextAppearances).
  4. Udfør enhver unik styling direkte i dit layout.

Vis noget stil

Selvom du direkte kan indstille TextView-attributter i dit layout, kan denne fremgangsmåde være kedelig og med fejl udsat. Forestil dig at prøve at opdatere farven på alle tekstvisninger i din app på denne måde . Som med alle visninger kan du i stedet (og bør!) Bruge stilarter til at fremme konsistens, genbrug og aktivere lette opdateringer. Til dette formål vil jeg anbefale at oprette stilarter til tekst, når du sandsynligvis vil anvende den samme styling til flere visninger. Dette er ekstremt enkelt og håndteres stort set af Android-visningssystemet.

Hvad sker der under hætten, når du sætter en stil på en visning? Hvis du nogensinde har skrevet en brugerdefineret visning, har du sandsynligvis set et opkald til context.obtainStyledAttributter (AttributeSet, int [], int, int). Sådan leverer Android-visningssystemet de attributter, der er specificeret i dit layout til visningen. AttributeSet-parameteren kan i det væsentlige betragtes som et kort over de XML-parametre, du angiver i dit layout. Hvis dette AttributSet specificerer en stil, læses stilen først, derefter anvendes de attributter, der er angivet direkte på visningen, oven på det. På denne måde kommer vi til vores første præferencebestemmelse.

Vis> Style

Attributter, der er defineret direkte på en visning, altid “vinde” og vil tilsidesætte de, der er angivet i en stil. Bemærk, at kombinationen af ​​stil- og visningsattributter anvendes; definition af en attribut på en visning, der også vises i stilen, kasserer ikke hele stilen. Det er også interessant at bemærke, at der ikke er nogen reel måde i dine synspunkter til at bestemme, hvor styling kommer fra; det løses af visningssystemet for dig i dette enkelt opkald. Du kan ikke modtage begge dele og vælge.

Selvom stilarter er ekstremt nyttige, har de dog deres grænser. Den ene er, at du kun kan anvende en enkelt stil på en visning (i modsætning til noget som CSS på nettet, hvor du kan anvende flere klasser). TextView har dog et trick op i ærmet, det tilbyder en TextAppearance-attribut, der fungerer på samme måde som en stil. Hvis du leverer tekststyling via en TextAppearance, der lader stilattributten fri til anden styling, der lyder nyttigt. Lad os se nærmere på hvad TextAppearance er, og hvordan det fungerer.

TextAppearance

Der er intet magisk ved TextAppearance (som en hemmelig tilstand til at anvende flere stilarter, som Android ikke vil have dig til at vide om! 1!), TextView gør nogle meget nyttige benarbejder for dig. Lad os se på nogle af TextViews konstruktører for at se, hvad der foregår.

TypedArray a = tema.obtainStyledAttributter (attrs, com.android.internal.R.styleable.TextViewAppearance, defStyleAttr, defStyleRes);
TypedArray-udseende = null;
int ap = a.getResourceId (com.android.internal.R.styleable.TextViewAppearance_textAppearance, -1);
a.recycle ();
hvis (ap! = -1) {
  udseende = tema.obtainStyledAttributter (ap, com.android.internal.R.styleable.TextAppearance);
}
if (udseende! = null) {
  readTextAppearance (kontekst, udseende, attributter, falsk);
  appearance.recycle ();
}
// lidt senere
a = tema.obtainStyledAttributter (attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
readTextAppearance (kontekst, a, attributter, sandt);

Så hvad sker der her? I det væsentlige ser TextView først, hvis du har leveret android: textAppearance, hvis det er tilfældet, indlæses den stil og anvender alle egenskaber, den angiver. Senere indlæser det derefter alle attributter i visningen (som husker, inkluderer stilen) og anvender dem. Vi ankommer derfor til vores anden forrangsregel:

Vis> Style> TextAppearance

Da tekstudseendet først er markeret, tilsidesætter alle attributter, der defineres enten direkte i en visning eller i en stil, tekstudseendet.

Der er en anden advarsel, man skal være opmærksom på med TextAppearance, som er det, der understøtter en undergruppe af stylingattributter, som TextView tilbyder. Lad os gå tilbage til denne linje for at forstå dette:

fåStyledAttributter (ap, android.R.styleable.TextAppearance);

Vi har set på 4 arg-versionen af ​​fåStyledAttributter, denne 2 arg-version er lidt anderledes. Den ser i stedet på en given typografi (som identificeret ved den første id-parameter) og filtrerer den til kun attributterne i denne stil, som vises i den anden attrs array param. Som sådan definerer den stilbare android.R.styleable.TextAppearance omfanget af, hvad TextAppearance forstår. Ser vi på definitionen af ​​dette kan vi se, at TextAppearance understøtter mange, men ikke alle attributter, som TextView understøtter.
















Stylingattributter understøttet af TextAppearances

Nogle almindelige TextView-attributter, der ikke er inkluderet, er lineHeight [Multiplier | Extra], linjer, breakStrategy & hyphenationFrequency. TextAppearance fungerer på tegneniveau, ikke afsnit, så attributter, der påvirker hele layoutet, understøttes ikke.

Så TextAppearance er meget nyttigt, det giver os mulighed for at definere en stil med fokus på tekststylingegenskaber og efterlader en visnings stil gratis til anden brug. Det har dog et begrænset omfang og er i bunden af ​​forrangskæden, så vær opmærksom på dens begrænsninger.

Fornuftige standarder

Da vi kiggede på, hvordan Android-visningssystemet løste attributter (context.obtainStyledAttributter), forenklede vi tingene lidt. Dette kalder op til theme.obtainStyledAttributter (ved hjælp af det aktuelle tema i konteksten). Ved at kontrollere referencen vises dette den rækkefølge, vi kiggede på før, og specificerer yderligere 2 steder, det ser ud til at løse attributter: visningens standardstil og tema.

Stylingpræferenceordren fra temadokumentation

Vi vender tilbage til temaet, men lad os se på standardformater. Hvad pokker er en standardstil? For at svare på dette synes jeg det er illustrerende at tage en hurtig omvej fra TextView og se på den ydmyge knap. Når du slipper en i dit layout, ser det sådan ud.

En standard knap

Hvorfor? Hvis du ser på kildekoden til knappen, er den temmelig sparsom:

knap for offentlig klasse udvider TextView {
  offentlig knap (kontekstkontekst) {
    dette (kontekst, null);
  }
  offentlig knap (kontekstkontekst, AttributeSet attrs) {
    dette (kontekst, attrs, com.android.internal.R.attr.buttonStyle);
  }
  offentlig knap (kontekstkontekst, AttributeSet attrs, int defStyleAttr) {
    dette (kontekst, attrs, defStyleAttr, 0);
  }
  offentlig knap (kontekstkontekst, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super (kontekst, attrs, defStyleAttr, defStyleRes);
  }
  @Override offentlig CharSequence getAccessibilityClassName () {
    return Button.class.getName ();
  }
  @Override offentlig PointerIcon onResolvePointerIcon (MotionEvent-begivenhed, int pointerIndex) {
    if (getPointerIcon () == null && isClickable () && isEnabled ()) {
      return PointerIcon.getSystemIcon (getContext (), PointerIcon.TYPE_HAND);
    }
    return super.onResolvePointerIcon (begivenhed, pointerIndex);
  }
}

Det er det! Hele klassen (færre kommentarer). Du kan tjekke her. Jeg venter. Så hvor kommer baggrunden, den aktiverede tekst, krusningen osv. Alle fra? Du har måske gået glip af det, men det er alt sammen i 2 arg konstruktøren; det, der kaldes, når et layout er oppustet fra XML. Det er den sidste parameter, der specificerer en defaultStyleAttr fra com.android.internal.R.attr.buttonStyle. Dette er standardformatet, som i det væsentlige er et indirekte punkt, der giver dig mulighed for at specificere en, vel, stil, der skal bruges som standard. Det peger ikke direkte på en stil, men lader dig pege på en i dit tema, som det vil kontrollere, når du løser attributter. Og det er nøjagtigt, hvad alle temaer, du typisk arver fra, gør for at give standardudseendet til fælles widgets. Når man for eksempel ser på Materiale-temaet, definerer det @ style / Widget.Material.Light.Button , og det er denne stil, der leverer alle de attributter, som theme.obtainStyledAttribute vil levere hvis du ikke angiver noget andet.

Når det går tilbage til TextView, tilbyder det også en standardstil: textViewStyle. Dette kan være meget praktisk, hvis du vil anvende noget styling på hver eneste TextView i din app. Sig, at du ville indstille en standardlinjeafstandsmultiplikator på 1,2 overalt. Du kan gøre dette gennem stilarter / TextAppearances og prøve at håndhæve dette gennem kodegennemgang (eller måske endda en dekorativ tilpasset fnugregel), men du skulle være opmærksom og være sikker på at ombord nye teammedlemmer og være forsigtig med refaktorer osv.

En bedre fremgangsmåde kan være at specificere din egen standardstil for alle TextViews i appen ved at kode den ønskede opførsel. Du kan gøre dette ved at indstille din egen stil til textViewStyle, der strækker sig fra platformen eller MaterialComponents / AppCompat standard.