Das Anzeigen von Textinformationen ist wahrscheinlich der grundlegendste und wichtigste Teil vieler Android-Anwendungen. In diesem Artikel wird über TextView gesprochen. Jeder Entwickler, beginnend mit „Hello World“, ist ständig mit diesem Element der Benutzeroberfläche konfrontiert. Wenn Sie mit Text arbeiten, müssen Sie von Zeit zu Zeit darüber nachdenken, verschiedene Designlösungen zu implementieren oder die Leistung beim Rendern des Bildschirms zu verbessern.
Ich werde über das TextView-Gerät und einige Feinheiten der Arbeit damit sprechen. Die wichtigsten Tipps stammen aus Berichten früherer Google I / O.
TextView unter der Haube
Zum Rendern von Text in Android wird ein ganzer Stapel verschiedener Bibliotheken unter der Haube verwendet. Sie können in zwei Hauptteile unterteilt werden - Java-Code und nativer Code:
Java-Code ist im Wesentlichen Teil des Android SDK, das Anwendungsentwicklern zur Verfügung steht, und neue Funktionen können in die Support-Bibliothek portiert werden.
Der TextView-Kern selbst ist in C ++ geschrieben, wodurch die Portierung neuer Funktionen, die dort von neuen Versionen des Betriebssystems implementiert wurden, auf die Unterstützungsbibliothek beschränkt wird. Der Kern sind die folgenden Bibliotheken:
- Minikin wird verwendet, um die Länge von Text, Zeilenumbrüchen und Wörtern anhand von Silben zu messen.
- Die Intensivstation bietet Unicode-Unterstützung.
- HarfBuzz findet für Unicode-Zeichen die entsprechenden grafischen Elemente (Glyphen) in Schriftarten.
- FreeType erstellt Bitmaps von Glyphen.
- Skia ist eine Engine zum Zeichnen von 2D-Grafiken.
Messen von Textlänge und Zeilenumbrüchen
Wenn Sie die Zeile an die Minikin-Bibliothek übergeben, die in der Textansicht verwendet wird, bestimmt sie zunächst, aus welchen Glyphen die Zeile besteht:
Wie Sie in diesem Beispiel sehen können, ist das Abgleichen von Unicode-Zeichen mit Glyphen nicht immer eins zu eins: Hier entsprechen 3 Zeichen gleichzeitig einem ffi-Glyphen. Darüber hinaus ist darauf zu achten, dass die erforderlichen Glyphen in verschiedenen Systemschriftarten enthalten sind.
Das Finden von Glyphen nur in Systemschriftarten kann zu Schwierigkeiten führen, insbesondere wenn Symbole oder Emojis durch Zeichen angezeigt werden und Zeichen aus verschiedenen Schriftarten in einer Zeile kombiniert werden sollen. Ab Android Q (29) war es daher möglich, eine eigene Liste der mit der Anwendung gelieferten Schriftarten zu erstellen. Diese Liste wird verwendet, um nach Glyphen zu suchen:
textView.typeface = TypeFace.CustomFallbackBuilder( FontFamily.Builder( Font.Builder(assets, “lato.ttf”).build() ).build() ).addCustomFallback( FontFamily.Builder( Font.Builder(assets, “kosugi.ttf”).build() ).build() ).build()
CustomFallbackBuilder
jetzt CustomFallbackBuilder
Zeichen mit Glyphen CustomFallbackBuilder
das SDK die angegebene Schriftfamilie in der angegebenen Reihenfolge. Wenn sie nicht gefunden werden kann, wird die Suche in Systemschriftarten fortgesetzt (und über die Methode setSystemFallback()
können Sie die bevorzugte Systemschriftfamilie angeben). CustomFallbackBuilder
hat eine Begrenzung für die Anzahl der Schriftfamilien - Sie können nicht mehr als 64 Schriftarten hinzufügen.
Die Minikin-Bibliothek teilt Zeichenfolgen in Wörter auf und misst einzelne Wörter. Um die Arbeit zu beschleunigen, wird ab Lollipop (21) ein System- LRU- Wortcache verwendet. Ein solcher Cache bietet einen enormen Leistungsgewinn: Ein Aufruf von Paint.measureText()
für ein zwischengespeichertes Wort Paint.measureText()
durchschnittlich 3% der Zeit, in der es zuerst seine Größe berechnet.
Wenn der Text nicht der angegebenen Breite entspricht, ordnet Minikin Zeilenumbrüche und Wörter im Text an. Beginnend mit Marshmallow (23) können Sie sein Verhalten steuern, indem Sie die speziellen Attribute breakStrategy
und HyphenationFrequency für TextView angeben.
Mit dem Wert breakStrategy=simple
ordnet breakStrategy=simple
Bibliothek die Bindestriche einfach nacheinander an und durchläuft den Text: Sobald die Zeile nicht mehr passt, wird die Silbentrennung vor das letzte Wort gesetzt.
Bei dem balanced
Wert balanced
Bibliothek, Zeilenumbrüche so zu erstellen, dass die Zeilen in der Breite ausgerichtet sind.
high_quality
hat mit Ausnahme einiger Unterschiede fast das gleiche Verhalten wie balanced
(einer davon: In der vorletzten Zeile kann die Silbentrennung nicht nur aus getrennten Wörtern bestehen, sondern auch aus Wörtern nach Silben).
Mit dem Attribut hyphenationFrequency
können hyphenationFrequency
die Strategie für den Zeilenumbruch nach Silben steuern. Ein Wert von none
führt keine automatische Silbentrennung durch, normal
führt zu einer geringen Silbentrennungshäufigkeit und full
dementsprechend die maximale Anzahl von Wörtern.
Leistung beim Rendern von Text in Abhängigkeit von den ausgewählten Flags (gemessen mit Android P (28) ):
Angesichts eines ziemlich starken Leistungseinbruchs haben Google-Entwickler, beginnend mit Version Q (29) und AppCompat 1.1.0 , beschlossen, die Silbentrennung standardmäßig zu deaktivieren . Wenn der Zeilenumbruch in der Anwendung wichtig ist, müssen Sie ihn jetzt explizit aktivieren.
Bei der Verwendung von Zeilenumbruch muss berücksichtigt werden, dass die aktuell ausgewählte Sprache im Betriebssystem den Betrieb der Bibliothek beeinflusst. Je nach Sprache wählt das System spezielle Wörterbücher mit Übertragungsregeln aus.
Textstile
Es gibt verschiedene Möglichkeiten, Text in Android zu formatieren:
- Ein einzelner Stil , der für das gesamte TextView-Element gilt.
- Multi-Style (Multi-Style) - Mehrere Stile gleichzeitig, die auf der Ebene von Absätzen oder einzelnen Zeichen auf den Text angewendet werden können. Es gibt verschiedene Möglichkeiten, dies zu tun:
- Zeichnen von Text auf Leinwand
- HTML-Tags
- spezielle Markup-Elemente - Spannweiten
Ein einzelner Stil impliziert die Verwendung von XML-Stilen oder XML-Attributen im TextView-Markup. In diesem Fall wendet das System die Werte aus den Ressourcen in der folgenden Reihenfolge an: TextAppearance, Thema (Thema), Standardstil (Standardstil), Stil aus der Anwendung, und die höchste Priorität haben die Werte der Ansichtsattribute.
Die Verwendung von Ressourcen ist eine recht einfache Lösung, die es Ihnen jedoch leider nicht ermöglicht, Stil auf Teile des Textes anzuwenden.
HTML-Tags sind eine weitere einfache Lösung, die Funktionen wie das Fett- und Kursivieren einzelner Wörter oder sogar das Hervorheben von Listen mit Punkten im Text bietet. Der Entwickler muss Html.fromHtml()
Methode Html.fromHtml()
aufrufen, mit der der markierte Text in Text umgewandelt wird, der durch Html.fromHtml()
gekennzeichnet ist. Diese Lösung verfügt jedoch nur über eingeschränkte Funktionen, da sie nur einen Teil der HTML-Tags erkennt und keine CSS-Stile unterstützt.
val text = "My text <ul><li>bullet one</li><li>bullet two</li></ul>" myTextView.text = Html.fromHtml(text)
Es können verschiedene Methoden zum Stylen von TextView kombiniert werden. Beachten Sie jedoch die Priorität einer bestimmten Methode, die sich auf das Endergebnis auswirkt:
Eine andere Möglichkeit - das Zeichnen von Text auf der Leinwand - gibt dem Entwickler die volle Kontrolle über die Textausgabe: Sie können beispielsweise Text entlang einer gekrümmten Linie zeichnen. Eine solche Lösung kann jedoch je nach den Anforderungen sehr schwierig zu implementieren sein und geht über den Rahmen dieses Artikels hinaus.
Spannweiten
TextView verwendet Bereiche, um Stile zu optimieren. Mithilfe von Bereichen können Sie die Farbe einer Reihe von Zeichen ändern, einen Teil des Texts als Links festlegen, die Größe des Texts ändern, einen Punkt vor einem Absatz zeichnen usw.
Die folgenden Kategorien von Bereichen können unterschieden werden:
- Zeichenspannen - werden auf Zeichenebene einer Zeichenfolge angewendet.
- Aussehen beeinflusst - Ändern Sie nicht die Textgröße.
- Metrik beeinflusst - Ändert die Größe von Text.
- Absatzbereiche - werden auf Absatzebene angewendet.
Das Android-Framework verfügt über Schnittstellen und abstrakte Klassen mit Methoden, die während onMeasure()
und beim Rendern von TextView aufgerufen werden. Diese Methoden ermöglichen Spannen den Zugriff auf untergeordnete Objekte wie TextPaint
und Canvas
. Mithilfe der Spanne überprüft das Android-Framework, welche Schnittstellen dieses Objekt implementiert, um die erforderlichen Methoden aufzurufen.
Das Android-Framework definiert mehr als 20 Bereiche. Bevor Sie Ihre eigenen erstellen, sollten Sie überprüfen, ob das SDK geeignet ist.
Aussehen gegen Metrik, die die Spannweiten beeinflusst
Die erste Kategorie von Bereichen wirkt sich darauf aus, wie die Zeichen in der Zeichenfolge aussehen: Zeichenfarbe, Hintergrundfarbe, unterstrichene oder durchgestrichene Zeichen usw. Diese UpdateAppearance
implementieren die UpdateAppearance
Schnittstelle und erben von der CharacterStyle
Klasse, die den Zugriff auf das TextPaint
Objekt ermöglicht.
Die Metrik, die sich auf die Spanne auswirkt, wirkt sich auf die Größe des Texts und des Layouts aus. Daher erfordert die Verwendung einer solchen Spanne nicht nur das Neuzeichnen der Textansicht, sondern auch den Aufruf von onMeasure()
/ onLayout()
. Diese MetricAffectingSpan
werden normalerweise von der MetricAffectingSpan
Klasse geerbt, die von dem oben erwähnten CharacterStyle
erbt.
Zeichen gegen Absatz, der die Spannweiten beeinflusst
Die Absatzspanne wirkt sich auf einen ganzen Textblock aus: Sie kann die Ausrichtung, den Einzug oder sogar das Einfügen eines Punkts am Anfang eines Absatzes ändern. Solche Bereiche sollten von der ParagraphStyle
Klasse geerbt und genau vom Anfang des Absatzes bis zu seinem Ende in den Text eingefügt werden. Wenn der Bereich falsch ist, funktioniert die Spanne nicht.
Unter Android werden Absätze als Teil des Textes betrachtet, der durch Zeilenumbrüche ( \n
) getrennt ist.
Schreiben Sie Ihre Spannweiten
Wenn Sie Ihre eigenen Bereiche schreiben, müssen Sie entscheiden, welche Auswirkungen der Bereich haben soll, um auszuwählen, von welcher Klasse geerbt werden soll:
- Beeinflusst Text auf Zeichenebene ->
CharacterStyle
- Beeinflusst Text auf Absatzebene ->
ParagraphStyle
UpdateAppearance
→ UpdateAppearance
- Beeinflusst die Textgröße -
UpdateLayout
Hier ist ein Beispiel für eine Spanne zum Ändern der Schriftart:
class CustomTypefaceSpan(private val font: Typeface?) : MetricAffectingSpan() { override fun updateMeasureState(textPaint: TextPaint) = update(textPaint) override fun updateDrawState(textPaint: TextPaint) = update(textPaint) fun update(textPaint: TextPaint) { textPaint.apply { val old = typeface val oldStyle = old?.style ?: 0 val font = Typeface.create(font, oldStyle) typeface = font
Stellen Sie sich vor, wir möchten einen eigenen Bereich zum Hervorheben von Codeblöcken erstellen. Dazu bearbeiten wir unseren vorherigen Bereich. Nach dem Festlegen der Schriftart fügen wir eine Änderung in der Hintergrundfarbe des Texts hinzu:
class CodeBlockSpan(private val font: Typeface?) : MetricAffectingSpan() { … fun update(textPaint: TextPaint) { textPaint.apply {
Wenden Sie span auf den Text an:
Sie können jedoch genau das gleiche Ergebnis CustomTypefaceSpan
indem Sie zwei CustomTypefaceSpan
kombinieren: Nehmen Sie unseren vorherigen CustomTypefaceSpan
und BackgroundColorSpan
aus dem Android-Framework:
Diese beiden Lösungen werden einen Unterschied haben. Tatsache ist, dass selbstgeschriebene Parcelable
die Parcelable
Schnittstelle im Gegensatz zu Systembereichen nicht implementieren können.
Bei der Übertragung einer stilisierten Linie durch Intent oder die Zwischenablage wird im Falle einer Zeitspanne von selbst geschriebenem Markup nicht gespeichert. Bei Verwendung von Bereichen aus dem Framework bleibt das Markup erhalten.
Verwenden von Bereichen im Text
Es gibt zwei Schnittstellen für stilisierten Text im Framework: Spanned
und Spannable
(mit unverändertem bzw. veränderbarem Markup) und drei Implementierungen: SpannedString
(unveränderter Text), SpannableString
(unveränderter Text) und SpannableStringBuilder
(veränderbarer Text).
SpannableStringBuilder
wird beispielsweise in einem EditText
, der Text ändern muss.
Sie können einer Zeile mit der folgenden Methode einen neuen Bereich hinzufügen:
setSpan(Object what, int start, int end, int flags)
Die Spanne wird durch den ersten Parameter geleitet, dann wird der Bereich der Indizes im Text angezeigt. Und der letzte Parameter kann gesteuert werden, wie sich der Bereich beim Einfügen von neuem Text verhält: ob sich der Bereich auf den am Start- oder Endpunkt eingefügten Text ausbreitet (wenn Sie neuen Text in der Mitte einfügen, wird der Bereich unabhängig von den Flag-Werten automatisch auf ihn angewendet) .
Die oben aufgeführten Klassen unterscheiden sich nicht nur semantisch, sondern auch in ihrer internen SpannedString
: SpannedString
und SpannableString
verwenden Arrays zum Speichern von Spannen, und SpannableStringBuilder
verwendet einen Intervallbaum .
Wenn Sie Tests für die Geschwindigkeit des Renderns von Text in Abhängigkeit von der Anzahl der Bereiche durchführen, erhalten Sie die folgenden Ergebnisse: Wenn Sie bis zu ~ 250 SpannableString
hintereinander verwenden, arbeiten SpannableString
und SpannableStringBuilder
ungefähr mit der gleichen Geschwindigkeit. Wenn die Markup-Elemente jedoch mehr als 250 SpannableString
, wird SpannableString
zu verlieren. Wenn die Aufgabe darin besteht, einen Stil auf einen Text anzuwenden, sollte man sich bei der Auswahl einer Klasse an den semantischen Anforderungen orientieren: ob die Linie und die Stile veränderbar sind. Wenn für das Markup jedoch mehr als 250 SpannableStringBuilder
erforderlich sind, sollten Sie SpannableStringBuilder
immer SpannableStringBuilder
.
Überprüfen Sie den Text auf Spanne
Die Aufgabe besteht regelmäßig darin, zu überprüfen, ob eine überspannte Linie eine bestimmte Spanne hat. Und auf Stackoverflow finden Sie diesen Code:
fun <T> hasSpan(spanned: Spanned, clazz: Class<T>): Boolean { val spans: Array<out T> = spanned.getSpans(0, spanned.length, clazz) return spans.isNotEmpty() }
Eine solche Lösung funktioniert, ist jedoch ineffizient: Sie müssen alle Bereiche durchgehen, prüfen, ob jeder von ihnen zum übergebenen Typ gehört, das Ergebnis in einem Array sammeln und am Ende nur überprüfen, ob das Array nicht leer ist.
Eine effektivere Lösung wäre die Verwendung der nextSpanTransition()
-Methode:
fun <T> hasSpan(spanned: Spanned, clazz: Class<T>): Boolean { val limit = spanned.length return spanned.nextSpanTransition(0, limit, clazz) < limit }
Textmarkup in verschiedenen Sprachressourcen
Eine solche Aufgabe kann auftreten, wenn Sie ein bestimmtes Wort mithilfe von Markups in verschiedenen Zeichenfolgenressourcen hervorheben möchten. Zum Beispiel müssen wir das Wort "Text" in der englischen Version und " Text " in der spanischen Version hervorheben:
<string name="title">Best practices for text in Android</string> <string name=”title”>Texto en Android: mejores prácticas</string>
Wenn Sie beispielsweise etwas Einfaches benötigen, um das Wort fett hervorzuheben, können Sie die üblichen HTML-Tags ( <b>
) verwenden. In der Benutzeroberfläche müssen Sie nur die Zeichenfolgenressource in der Textansicht festlegen:
textView.setText(R.string.title)
Wenn Sie jedoch etwas Komplexeres benötigen, z. B. das Ändern der Schriftart, kann HTML nicht mehr verwendet werden. Die Lösung besteht darin, das spezielle <annotation>
. Mit diesem Tag können Sie ein beliebiges Schlüssel-Wert-Paar in einer XML-Datei definieren. Wenn wir eine Zeichenfolge aus Ressourcen ziehen, werden diese Tags automatisch in Annotation
konvertiert, die im Text mit den entsprechenden Schlüsseln und Werten angeordnet sind. Danach können Sie die Liste der Anmerkungen im Text analysieren und die erforderlichen Bereiche anwenden.
Angenommen, wir müssen die Schriftart mit CustomTypefaceSpan
.
Fügen Sie ein Tag hinzu und definieren Sie einen "Schriftart" -Schlüssel und einen Wert - die Art der Schriftart, die wir verwenden möchten, ist "title_emphasis" :
<string name="title">Best practices for <annotation font=”title_emphasis”>text</annotation> in Android</string> <string name=”title”><annotation font=”title_emphasis”>Texto</annotation> en Android: mejores prácticas</string>
Ziehen Sie die Zeichenfolge aus den Ressourcen, suchen Sie die Anmerkungen mit der Taste "Schriftart" und ordnen Sie die Bereiche an:
Es wurde oben erwähnt, dass Parcelable
von außerhalb des Android-Frameworks Parcelable
nicht implementieren Parcelable
und über Intent übertragen werden. Dies gilt jedoch nicht für Anmerkungen, die Parcelable
implementieren. So können Sie die mit Anmerkungen versehene Zeichenfolge durch Intent führen und genau auf die gleiche Weise analysieren, indem Sie Ihre Bereiche anordnen.
Wie Text in einer Textansicht platziert wird
TextView kann nicht nur Text, sondern auch Bilder anzeigen. Sie können auch verschiedene Einrückungen vor dem Text setzen. Unter der Haube funktioniert dies so, dass TextView eine untergeordnete Klasse, Layout, erstellt, die direkt für die Anzeige von Text verantwortlich ist. Dies ist eine abstrakte Klasse mit drei Implementierungen. Normalerweise müssen Sie nicht direkt mit ihnen arbeiten, es sei denn, Sie schreiben Ihr eigenes Steuerelement:
- BoringLayout wird für einfache Texte verwendet, unterstützt keine Zeilenumbrüche , RTL und andere Dinge, ist aber das leichteste. TextView verwendet es, wenn der Text alle Einschränkungen erfüllt.
- StaticLayout wird in TextView für andere Fälle verwendet.
- DynamicLayout wird für veränderlichen Text in einem EditText verwendet.
Das Layout verfügt über viele Methoden, mit denen Sie die verschiedenen Parameter des angezeigten Textes kennenlernen können: die Koordinaten der Linien, die Grundlinie, die Koordinaten des Anfangs- und Endes des Textes in der Linie usw. (Weitere Details finden Sie in der Dokumentation )
Solche Methoden können sehr nützlich sein. Einige Entwickler stehen beispielsweise vor der Aufgabe, einen Teil des Textes in abgerundete Rechtecke zu extrahieren und zu versuchen, seine Lösung über Bereiche zu finden, die zur Lösung dieses Problems nicht anwendbar sind.
Aber Methoden der Layout-Klasse können Abhilfe schaffen. Hier ist eine Beispiellösung:
Mithilfe von Anmerkungen wählen wir die Wörter aus, die in Rechtecken eingekreist werden sollen.
Erstellen Sie dann 4 zeichnbare Ressourcen für alle Fälle von Textumbruch, die in Rechtecke eingeschlossen werden sollten:
Als nächstes finden wir die Anmerkungen, die wir im Text benötigen, wie oben beschrieben. Jetzt haben wir die Indizes für den Anfang und das Ende einer solchen Anmerkung. Mithilfe der Layout-Methoden können Sie die Nummer der Zeile ermitteln, in der der kommentierte Text beginnt und in der er endet:
val startLine = layout.getLineForOffset(spanStartIndex) val endLine = layout.getLineForOffset(spanEndIndex)
Als nächstes müssen Sie ein oder mehrere Rechtecke zeichnen. Betrachten Sie den einfachen Fall, in dem der mit Anmerkungen versehene Teil des Textes in einer Zeile angezeigt wurde, dann benötigen wir nur ein Rechteck mit vier abgerundeten Ecken. Definieren Sie die Koordinaten und zeichnen Sie:
... if (startLine == endLine) { val lineTop = layout.getLineTop(startLine)
Wie Sie diesem Beispiel entnehmen können, speichert Layout viele nützliche Informationen zum angezeigten Text, die bei der Implementierung verschiedener nicht standardmäßiger Aufgaben hilfreich sein können.
TextView-Leistung
TextView durchläuft wie jede Ansicht bei der Anzeige drei Phasen: onMeasure()
, onLayout()
und onDraw()
. Gleichzeitig benötigt onMeasure()
im Gegensatz zu den beiden anderen Methoden die meiste Zeit: In diesem Moment wird die Layout-Klasse neu erstellt und die Textgröße berechnet. Das Ändern der Textgröße (z. B. das Ändern der Schriftart) ist daher mit viel Arbeit verbunden. Das Ändern der onDraw()
da nur onDraw()
. Wie oben erwähnt, verfügt das System über einen globalen Wortcache mit berechneten Größen. Befindet sich das Wort bereits im Cache, onMeasure()
das onMeasure()
Aufrufen von onMeasure()
11-16% der Zeit, die für eine vollständige Berechnung erforderlich gewesen wäre.
Textbeschleunigung
Im Jahr 2015 haben Instagram-Entwickler die Anzeige von Kommentaren zu Fotos mithilfe des globalen Caches beschleunigt. Die Idee war, den Text virtuell zu zeichnen, bevor er auf dem Bildschirm angezeigt wird, um so den Systemcache „aufzuwärmen“. Als es Zeit war, den Text anzuzeigen, sah der Benutzer ihn viel schneller, da der Text bereits gemessen wurde und sich im Cache befand.
Beginnend mit Android P (28) haben Google-Entwickler der API die Möglichkeit hinzugefügt, die Phase der Messung der Textgröße im Hintergrund-Thread - PrecomputedText
(und den Backport für die API ab Android I (14) - PrecomputedTextCompat
) im Voraus PrecomputedTextCompat
. Mit der neuen API werden 90% der Arbeit im Hintergrund-Thread erledigt.
Ein Beispiel:
Großen Text anzeigen
Wenn Sie großen Text anzeigen müssen, übertragen Sie ihn nicht sofort in eine Textansicht. Andernfalls funktioniert die Anwendung möglicherweise nicht mehr reibungslos oder friert vollständig ein, da der Hauptthread viel Arbeit leistet, um großen Text anzuzeigen, den der Benutzer möglicherweise nicht einmal bis zum Ende scrollen kann. Die Lösung besteht darin, den Text in Teile (z. B. Absätze) aufzuteilen und die einzelnen Teile in der RecyclerView anzuzeigen. Für eine noch schnellere Beschleunigung können Sie die Größe von Textblöcken mit PrecomputedText vorberechnen.
Um das Einbetten von PrecomputedText in RecyclerView zu erleichtern, haben Google-Entwickler spezielle Methoden für PrecomputedTextCompat.getTextFuture()
und AppCompatTextView.setTextFuture()
:
fun onBindViewHolder(vh: ViewHolder, position: Int) { val data = getData(position) vh.textView.setTextSize(...) vh.textView.setFontVariationSettings(...)
RecyclerView , , , .
, getTextFuture()
(, ), , , getTextFuture()
, , TextView.
, TextView
TextView.setText()
:
if (type == SPANNABLE || movementMethod != null) { text = spannableFactory.newSpannable(spannable)
span' TextView, setText()
, .
, . TextView , -, . , . , , TextView spannableFactory
:
class MySpannableFactory : Spannable.Factory() { override fun newSpannable(source: CharSequence): Spannable { return source as? Spannable ?: super.newSpannable(source) } } textView.spannableFactory = MySpannableFactory()
textView.setText(spannable, BufferType.SPANNABLE)
, .
Google span' RecyclerView, .
TextView, span, setText()
. TextView span. TextView spannable- span', :
val spannable = textView.getText() as Spannable val span = CustomTypefaceSpan(span) spannable.setSpan(span, ...)
span, TextView, TextView . , invalidate()
, – requestLayout()
:
val spannable = textView.getText() as Spannable val span = CustomTypefaceSpan(span) spannable.setSpan(span, ...) span.setTypeface(anotherTypeface) textView.requestLayout()
autoLink
TextView . autoLink
. autoLink=”web”
TextView URL URLSpan
. , SDK setText()
:
spannable = new SpannableString(string); Matcher m = pattern.matcher(text); while (...) {
UI , autoLink=”web”
RecyclerView. . LinkifyCompat
:
autoLink
map
– ( all
). . , WebView, ! SDK Linkify.gatherMapLinks()
, :
while ((address = WebView.findAddress(string)) != null) { ... }
WebView TODO SDK:
public static String findAddress(String addr) {
? Smart Linkify, Android P (28) , , . :
Linkify, . toolbar , Google .
Smart Linkify : , .
Magnifier
Android P (28) , – Magnifier, . .
TextView, EditText WebView, : API .
Fazit
Android , , :
- , Google I/O'19 “Best Practices for Using Text in Android” .
Nützliche Links
Artikel
Berichte