Nachdem ich auf Google IO 2019 einen Vortrag über Android Jetpack Compose gesehen hatte , wollte ich ihn sofort ausprobieren. Darüber hinaus erinnerte der darin implementierte Ansatz Flutter sehr, an dem ich früher interessiert war .

Die Compose-Bibliothek selbst befindet sich in der Pre-Alpha-Phase, sodass nicht viele Dokumentationen und Artikel darüber verfügbar sind. Als nächstes werde ich mich auf mehrere Ressourcen stützen, die ich gefunden habe, sowie auf die Open-Source-Bibliothek .
Diese Ressourcen sind:
Was ist Android Jetpack Compose?
Bisher basierte die gesamte Android-Benutzeroberfläche auf der View-Klasse. Dies ist seit den Anfängen von Android der Fall. In dieser Hinsicht haben sich viele Vermächtnisse und architektonische Mängel angesammelt, die verbessert werden könnten. Dies zu tun ist jedoch ziemlich schwierig, ohne den gesamten Code zu brechen, der auf ihrer Basis geschrieben wurde.
In den letzten Jahren sind in der Welt der Clientanwendungen (einschließlich Frontend-Trends) viele neue Konzepte aufgetaucht. Daher hat das Google-Team einen radikalen Weg eingeschlagen und die gesamte UI-Ebene in Android von Grund auf neu geschrieben. So erschien die Android Jetpack Compose-Bibliothek, die konzeptionelle Tricks von React, Litho, Vue, Flutter und vielen anderen enthält.
Lassen Sie uns einige der Funktionen der vorhandenen Benutzeroberfläche durchgehen und sie mit Compose vergleichen.
1. Unabhängigkeit von Android-Versionen
Die vorhandene Benutzeroberfläche ist eng mit der Plattform verbunden. Als die ersten Komponenten von Material Design erschienen, funktionierten sie nur mit Android 5 (API21) und höher. Um an älteren Versionen des Systems arbeiten zu können, müssen Sie die Support-Bibliothek verwenden.
Compose ist Teil von Jetpack, wodurch es unabhängig von den Systemversionen ist und auch in älteren Android-Versionen (zumindest mit API21) verwendet werden kann.
2. Die gesamte Kotlin-API
Zuvor mussten Sie sich mit verschiedenen Dateien befassen, um eine Benutzeroberfläche zu erstellen. Wir haben das Markup in XML beschrieben und dann den Java / Kotlin-Code verwendet, damit es funktioniert. Dann kehrten wir zu anderen XML-Dateien zurück, um Themen, Animationen, Navigation usw. festzulegen. Und versuchten sogar, Code in XML (Datenbindung) zu schreiben.
Mit Kotlin können Sie Benutzeroberflächen im deklarativen Stil direkt in Code anstelle von XML schreiben.
3. Composable = Composite: Verwenden von Komposition anstelle von Vererbung
Das Erstellen von benutzerdefinierten UI-Elementen kann ziemlich umständlich sein. Wir müssen von View oder seinem Nachkommen erben und uns um viele wichtige Eigenschaften kümmern, bevor es richtig gestartet wird. Beispielsweise enthält die TextView-Klasse ungefähr 30.000 Zeilen Java-Code. Dies liegt an der Tatsache, dass es eine Menge unnötiger Logik in sich enthält, die von untergeordneten Elementen geerbt wird.
Compose tauchte dagegen auf und ersetzte die Vererbung durch Komposition.
Padding
eignet sich am besten, um zu veranschaulichen, worum es geht:
Um in der vorhandenen Benutzeroberfläche die mit TextView
eingerückte 30dp
zu 30dp
:
Wir müssen den folgenden Code schreiben:
<TextView android:id="@+id/simpleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/cyan" android:padding="30dp" <------------------------ NOTE THIS android:text="Drag or tap on the seek bar" />
Dies bedeutet, dass irgendwo in TextView.java oder seinen Oberklassen eine Logik vorhanden ist, die weiß, wie Einrückungen gezählt und gezeichnet werden.
Mal sehen, wie Sie dasselbe in Compose tun können:
Änderungen
TextView
nur noch Text()
. Die android:padding
Eigenschaft wurde in ein Padding
, das Text
umschließt.
Die Vorteile
Daher ist Text
nur für das Rendern des Textes selbst verantwortlich. Er weiß nicht, wie man Einrückungen zählt. Padding
hingegen ist nur für das Auffüllen verantwortlich und nicht mehr. Es kann um jedes andere Element verwendet werden.
4. Unidirektionaler Datenstrom
Der unidirektionale Datenfluss ist ein wichtiges Konzept, wenn wir beispielsweise über die Steuerung des Status einer CheckBox
in einem vorhandenen UI-System CheckBox
. Wenn der Benutzer auf das CheckBox
, wird sein Status checked = true
: Die Klasse aktualisiert den CheckBox
und ruft einen Rückruf von dem Code auf, der die CheckBox
überwacht.
Dann müssen Sie im Code selbst, beispielsweise in ViewModel
, die entsprechende Statusvariable aktualisieren. Sie haben jetzt zwei Kopien des gedrückten Status, was zu Problemen führen kann. Wenn Sie beispielsweise den Wert der Statusvariablen im ViewModel
CheckBox
wird die CheckBox
aktualisiert, was in einer Endlosschleife enden kann. Um dies zu vermeiden, müssen wir uns eine Art Krücke einfallen lassen.
Die Verwendung von Compose hilft bei der Lösung dieser Probleme, da es auf dem Prinzip der Einseitigkeit basiert. Die Zustandsänderung wird innerhalb des Frameworks verarbeitet: Wir geben das Datenmodell einfach nach innen. Außerdem ändert die Komponente in Compose jetzt ihren Status nicht mehr von selbst. Stattdessen wird nur ein Rückruf aufgerufen, und jetzt ist es die Aufgabe der Anwendung, die Benutzeroberfläche zu ändern.
5. Verbessern des Debuggens
Da die gesamte Benutzeroberfläche jetzt in Kotlin geschrieben ist, können Sie die Benutzeroberfläche jetzt debuggen. Ich habe das nicht selbst versucht, aber im Podcast wurde gesagt, dass Debugger und Haltepunkte in Compose funktionieren.
Genug Wörter, zeigen Sie den Code
Ich weiß, ich möchte schnell sehen, wie die Benutzeroberfläche im Code aussieht (Spoiler: sehr ähnlich zu Flutter, wenn Sie versucht haben, darauf zu schreiben).
Zunächst erstellen wir einige einfache View
und vergleichen dann, wie sie in der vorhandenen Benutzeroberfläche und in Compose aussehen.
1. FrameLayout
vs Wrap + Padding + Background
Wir verwenden unser Beispiel oben erneut und versuchen, diese TextView
mit 30dp
und türkisfarbenem Hintergrund 30dp
:
Bestehende Benutzeroberfläche:
<TextView android:id="@+id/simpleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/cyan" <-------------- NOTE THIS android:padding="30dp" <------------------------ AND THIS android:text="Drag or tap on the seek bar" />
Schauen Sie sich nun den Code an, der in Compose dasselbe tut:
@Composable fun MyText() { Wrap { Padding(30.dp) { DrawRectangle(color = Color.Cyan) Text("Drag or tap on the seek bar") } } }
Hier sind ein paar neue Dinge. Da Text
nur das Rendern von Text kennt, sind Auffüllen und Hintergrund nicht wichtig. Um sie hinzuzufügen, müssen wir daher drei separate Funktionen verwenden:
DrawRectangle
HintergrundPadding
auffüllenWrap
ist eine Funktion, die Parameter wie FrameLayout
überlagert.
Einfach. Es unterscheidet sich jedoch geringfügig von dem bestehenden UI-System, an das wir alle gewöhnt sind.
2. Vertikales LinearLayout
gegen Column
Versuchen wir nun, etwas zu tun, das unserem guten alten LinearLayout
.
Um zwei Elemente wie im Bild unten untereinander zu platzieren, können Sie Column
:
Der Code sieht folgendermaßen aus:
@Composable fun FormDemo() { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") Button(text = "Next") } }
Das im Column
Element Column
Element befindet sich vertikal untereinander.
2a. Einrückung
Sie haben wahrscheinlich bemerkt, dass sich Text und Schaltfläche zu nahe am Rand befinden. Padding
daher Padding
.
@Composable fun FormDemo() { Padding(10.dp) {
Es sieht besser aus:
2b. Intervalle
Wir können auch einige Einrückungen zwischen Text
und Button
hinzufügen:
@Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp)
Wie unser Bildschirm jetzt aussieht:
2c. Horizontales LinearLayout
gegen Row
Platzieren Sie den zweiten Knopf neben dem ersten:
Code dafür:
@Composable fun FormDemo() { Padding(10.dp) { Column(crossAxisAlignment = CrossAxisAlignment.Start) { Text("Click the button below: ") HeightSpacer(10.dp) Row {
Innerhalb der Row
beiden Schaltflächen horizontal. WidthSpacer
fügt den Abstand zwischen ihnen hinzu.
2d. Gravity
gegen Alignment
Richten Sie unsere Elemente in der Mitte aus, wie es die gravity
in der aktuellen Benutzeroberfläche tut. Um diff zu zeigen, werde ich die alten Zeilen auskommentieren und durch neue ersetzen:
@Composable fun FormDemo() { Padding(10.dp) {
Wir werden Erfolg haben:
Mit crossAxisAlignment = CrossAxisAlignment.Center
verschachtelte Elemente horizontal zentriert. Wir sollten den Row
Parameter auch auf mainAxisSize = FlexSize.Min
, ähnlich wie layout_width = wrap_content
damit er sich aufgrund des Standardwerts mainAxisSize = FlexSize.Max
, der sich wie layout_width = match_parent
verhält, nicht über den Bildschirm layout_width = match_parent
.
2d. Bemerkung
Anhand der obigen Beispiele können Sie erkennen, dass alle Elemente aus separaten Funktionen zusammengesetzt sind: padding
ist eine separate Funktion, spacer
ist eine separate Funktion, anstatt Eigenschaften in Text
, Button
oder Column
.
Komplexere Elemente wie RecyclerView
oder ConstraintLayout
befinden sich in der Entwicklung. Daher konnte ich in den Demoquellen kein Beispiel dafür finden.
3. Stile und Themen
Sie haben wahrscheinlich bemerkt, dass die obigen Schaltflächen standardmäßig lila sind. Dies liegt daran, dass sie Standardstile verwenden. Mal sehen, wie Stile in Compose funktionieren.
In den obigen Beispielen ist FormDemo
mit der Annotation @Composable
. Jetzt werde ich zeigen, wie dieses Element in Activity
:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{ MaterialTheme { FormDemo() } } } }
Anstelle der Funktion setContentView()
verwenden wir setContent()
, eine Erweiterungsfunktion aus der Compose.kt
Bibliothek.
CraneWrapper
enthält den Compose-Baum und bietet Zugriff auf Context
, Density
, FocusManager
und TextInputService
.
MaterialTheme
können Sie das Thema für Elemente anpassen.
Zum Beispiel kann ich die Primärfarbe des Themas wie folgt in Braun ändern:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { CraneWrapper{
Jetzt sieht unser Bildschirm folgendermaßen aus:
Andere Farben und Schriftarten, die geändert werden können: MaterialTheme.kt # 57
Die Rallye-Aktivität bietet ein gutes Beispiel für das Anpassen eines Themas: Quellcode an RallyTheme.kt
Was zu sehen / zu lesen
Wenn Sie mehr möchten, können Sie das Beispielprojekt gemäß den Anweisungen hier zusammenstellen .
Wie Windows-Benutzer schreiben, gibt es jetzt keine offizielle Möglichkeit, Compose zu starten, aber es gibt eine inoffizielle Anleitung von kotlinlang Slack .
Fragen zu Compose können Entwicklern im Kanal #compose
kotlinlang Slack gestellt werden.
Lassen Sie andere Links in den Kommentaren - die nützlichsten werden hier hinzugefügt.
Schlussfolgerungen
Die Entwicklung dieser Bibliothek ist in vollem Gange, daher können sich die hier gezeigten Schnittstellen ändern. Es gibt noch viele Dinge, die Sie im Quellcode lernen können, wie z. B. @Model
und unidirektionaler Datenfluss (unidirektionaler Datenstrom). Vielleicht ist dies ein Thema für zukünftige Artikel.