Questa pagina fornisce una panoramica generale dei livelli di architettura che compongono Jetpack Compose e dei principi fondamentali alla base di questo design.
Jetpack Compose non è un singolo progetto monolitico, è creato da una serie di moduli assemblati per formare uno stack completo. Comprendere i diversi moduli che compongono Jetpack Compose ti consente di:
- Usa il livello di astrazione appropriato per creare la tua app o libreria
- Scopri quando puoi "scendere" a un livello inferiore per avere un maggiore controllo o personalizzazione
- Riduci al minimo le dipendenze
Livelli
I principali livelli di Jetpack Compose sono:
Figura 1. I principali livelli di Jetpack Compose.
Ogni livello è costruito sui livelli inferiori e combina le funzionalità per creare componenti di livello superiore. Ogni livello si basa su API pubbliche dei livelli inferiori per verificare i confini dei moduli e consentirti di sostituire qualsiasi livello se necessario. Esaminiamo questi livelli dal basso verso l'alto.
- Tempo di esecuzione
- Questo modulo fornisce le nozioni di base del runtime di Compose, ad esempio
remember
,mutableStateOf
, l'annotazione@Composable
eSideEffect
. Potresti prendere in considerazione la possibilità di creare direttamente su questo livello se hai bisogno solo delle funzionalità di gestione dell'albero di Compose, non della sua UI. - Interfaccia utente
- Il livello UI è costituito da più moduli (
ui-text
,ui-graphics
,ui-tooling
e così via). Questi moduli implementano le nozioni di base del toolkit UI, ad esempioLayoutNode
,Modifier
, gestori di input, layout personalizzati e disegno. Ti consigliamo di utilizzare questo livello se hai bisogno solo dei concetti fondamentali di un kit di strumenti per l'interfaccia utente. - Foundation
- Questo modulo fornisce componenti di base indipendenti dal sistema di progettazione per l'interfaccia utente di Compose, come
Row
eColumn
,LazyColumn
, il riconoscimento di determinati gesti e così via. Ti consigliamo di utilizzare il livello di base per creare il tuo sistema di progettazione. - Materiale
- Questo modulo fornisce un'implementazione del sistema Material Design per l'interfaccia utente di Compose, offrendo un sistema di temi, componenti stilizzati, indicazioni di effetto ripple e icone. Basati su questo livello quando utilizzi Material Design nella tua app.
Principi di progettazione
Un principio guida di Jetpack Compose è fornire funzionalità piccole e mirate che possono essere assemblate (o composte) insieme, anziché pochi componenti monolitici. Questo approccio presenta una serie di vantaggi.
Controllo
I componenti di livello superiore tendono a fare di più per te, ma limitano il controllo diretto che hai. Se hai bisogno di un maggiore controllo, puoi "abbassarti" per utilizzare un componente di livello inferiore.
Ad esempio, se vuoi animare il colore di un componente, puoi utilizzare l'API
animateColorAsState
:
val color = animateColorAsState(if (condition) Color.Green else Color.Red)
Tuttavia, se avevi bisogno che il componente fosse sempre grigio all'avvio, non puoi farlo con questa API. In alternativa, puoi utilizzare l'API di livello inferiore
Animatable
:
val color = remember { Animatable(Color.Gray) } LaunchedEffect(condition) { color.animateTo(if (condition) Color.Green else Color.Red) }
L'API animateColorAsState
di livello superiore è a sua volta basata sull'API Animatable
di livello inferiore. L'utilizzo dell'API di livello inferiore è più complesso, ma offre un maggiore controllo. Scegli il livello di astrazione più adatto alle tue esigenze.
Personalizzazione
Assemblare componenti di livello superiore da elementi di base più piccoli semplifica notevolmente la personalizzazione dei componenti, se necessario. Ad esempio, prendi in considerazione
l'implementazione
di
Button
fornita dal livello Material:
@Composable fun Button( // … content: @Composable RowScope.() -> Unit ) { Surface(/* … */) { CompositionLocalProvider(/* … */) { // set LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { Row( // … content = content ) } } } }
Un Button
è composto da 4 componenti:
Un materiale
Surface
che fornisce lo sfondo, la forma, la gestione dei clic e così via.Un
CompositionLocalProvider
che modifica l'alpha dei contenuti quando il pulsante è attivato o disattivatoUn
ProvideTextStyle
imposta lo stile di testo predefinito da utilizzareUn
Row
fornisce il criterio di layout predefinito per i contenuti del pulsante
Abbiamo omesso alcuni parametri e commenti per rendere la struttura più chiara, ma
l'intero componente è composto da circa 40 righe di codice perché assembla semplicemente questi 4 componenti per implementare il pulsante. Componenti come Button
hanno un'opinione su quali parametri esporre, bilanciando l'attivazione di personalizzazioni comuni con un'esplosione di parametri che può rendere un componente più difficile da utilizzare. I componenti Material, ad esempio, offrono personalizzazioni specificate nel sistema Material Design, semplificando l'applicazione dei principi di Material Design.
Tuttavia, se vuoi apportare una personalizzazione oltre i parametri di un componente, puoi "scendere" di un livello e eseguire il fork di un componente. Ad esempio, Material Design specifica che i pulsanti devono avere uno sfondo a tinta unita. Se hai bisogno di uno sfondo sfumato, questa opzione non è supportata dai parametri Button
. In questo caso, puoi utilizzare l'implementazione di Material Button
come riferimento e creare il tuo componente:
@Composable fun GradientButton( // … background: List<Color>, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background( Brush.horizontalGradient(background) ) ) { CompositionLocalProvider(/* … */) { // set material LocalContentAlpha ProvideTextStyle(MaterialTheme.typography.button) { content() } } } }
L'implementazione riportata sopra continua a utilizzare i componenti del livello Material, come i concetti di Material relativi all'alpha dei contenuti correnti e allo stile di testo corrente. Tuttavia, sostituisce il materiale Surface
con un Row
e applica lo stile per ottenere l'aspetto desiderato.
Se non vuoi utilizzare i concetti di Material, ad esempio se stai creando il tuo sistema di design personalizzato, puoi utilizzare solo i componenti del livello di base:
@Composable fun BespokeButton( // … backgroundColor: Color, modifier: Modifier = Modifier, content: @Composable RowScope.() -> Unit ) { Row( // … modifier = modifier .clickable(onClick = {}) .background(backgroundColor) ) { // No Material components used content() } }
Jetpack Compose riserva i nomi più semplici per i componenti di primo livello. Ad esempio,
androidx.compose.material.Text
è basato su
androidx.compose.foundation.text.BasicText
.
In questo modo è possibile fornire alla propria implementazione il nome più rilevabile se si desidera sostituire livelli superiori.
Scegliere l'astrazione giusta
Secondo la filosofia di Compose di creare componenti a più livelli riutilizzabili, non sempre dovresti raggiungere i componenti di base di livello inferiore. Molti componenti di livello superiore non solo offrono più funzionalità, ma spesso implementano best practice come il supporto dell'accessibilità.
Ad esempio, se volessi aggiungere il supporto dei gesti al tuo componente personalizzato, puoi crearlo da zero utilizzando Modifier.pointerInput
, ma ci sono altri componenti di livello superiore basati su questo che potrebbero offrire un punto di partenza migliore, ad esempio Modifier.draggable
Modifier.scrollable
o Modifier.swipeable
.
Come regola generale, preferisci creare il componente di livello più alto che offre la funzionalità di cui hai bisogno per usufruire delle best practice incluse.
Scopri di più
Consulta l'esempio Jetsnack per un esempio di creazione di un sistema di design personalizzato.
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Kotlin per Jetpack Compose
- Elenchi e griglie
- Effetti collaterali in Compose