Questa pagina descrive le best practice per lavorare con gli stili che garantiscono la coerenza in tutto il codebase, nonché i principi che abbiamo seguito durante la progettazione delle API.
Che cosa fare
Segui queste best practice:
Consigliato: utilizza gli stili per gli elementi visivi e i modificatori per i comportamenti
Utilizza l'API Styles per la configurazione visiva (sfondi, spaziatura interna, bordi) e riserva i modificatori per comportamenti come la logica di clic, il rilevamento dei gesti o l'accessibilità.
Azione consigliata: esporre i parametri di stile nei sistemi di progettazione
Per i tuoi componenti del sistema di progettazione personalizzati, devi esporre un oggetto Style
dopo il parametro del modificatore.
@Composable fun GradientButton( modifier: Modifier = Modifier, // ✅ DO: for design system components, expose a style modifier to consumers to be able to customize the components style: Style = Style ) { // Consume the style }
Azione consigliata: sostituisci i parametri basati sulla visualizzazione con uno stile
Valuta la possibilità di sostituire i parametri degli elementi componibili con un singolo parametro Style.
Ad esempio:
// Before @Composable fun OldButton(background: Color, fontColor: Color) { } // After // ✅ DO: Replace visual-based parameters with a style that includes same properties @Composable fun NewButton(style: Style = Style) { }
Consigli: dai la priorità agli stili per le animazioni
Utilizza il blocco animate integrato per lo stile basato sullo stato con animazioni per
migliorare le prestazioni rispetto ai modificatori.
Azione consigliata: sfrutta la strategia "L'ultima scrittura vince"
Sfrutta il fatto che le proprietà style vengono sovrascritte anziché impilate.
Utilizzalo per sostituire i bordi o gli sfondi predefiniti dei componenti senza
avere bisogno di più parametri.
Che cosa non fare
I seguenti pattern sono sconsigliati:
Non utilizzare gli stili per la logica di interazione
Non tentare di gestire il rilevamento di onClick o dei gesti all'interno di uno stile. Gli stili
sono limitati alle configurazioni visive basate sullo stato, pertanto non devono gestire
la logica di business. Devono invece avere solo un aspetto visivo diverso in base allo stato.
Sbagliato: fornire uno stile predefinito come parametro predefinito
I parametri di stile devono sempre essere dichiarati utilizzando style: Style = Style:
@Composable fun BadButton( modifier: Modifier = Modifier, // ❌ DON'T set a default style here as a parameter style: Style = Style { background(Color.Red) } ) { }
Per includere un parametro "default", unisci lo stile del parametro in entrata con quello predefinito:
@Composable fun GoodButton( modifier: Modifier = Modifier, // ✅ Do: always pass it as a Style, do not pass other defaults style: Style = Style ) { // ... val defaultStyle = Style { background(Color.Red) } // ✅ Do Combine defaults inside with incoming parameter Box(modifier = modifier.styleable(styleState, defaultStyle, style)) { // your logic } }
Non: fornire parametri di stile agli elementi componibili basati sul layout
Anche se puoi fornire uno stile a qualsiasi composable, non è previsto che i composable basati sul layout o a livello di schermo accettino uno stile. Dal punto di vista del consumatore, non è chiaro cosa farebbe uno stile a questo livello. Gli stili sono progettati per i componenti, non necessariamente per i layout.
Non: creare stili in Composizione
CompositionLocals vengono letti nel punto in cui viene definito lo stile, non dove viene
utilizzato. Quando lo stile viene effettivamente utilizzato, lo stato di CompositionLocal
potrebbe essere cambiato, con conseguente stile impreciso.
// DON'T - Create styles in Composition that access composition locals in this way - this will likely lead to issues when style is used / accessed, as it would not get updated when the value changes. @Composable fun containerStyle(): Style { val background = MaterialTheme.colorScheme.background val onBackground = MaterialTheme.colorScheme.onBackground return Style { background(background) contentColor(onBackground) } } // Do: Instead, Create StyleScope extension functions for your subsystems to access themed composition Locals val StyleScope.colors: JetsnackColors get() = JetsnackTheme.LocalJetsnackTheme.currentValue.colors val StyleScope.typography: androidx.compose.material3.Typography get() = JetsnackTheme.LocalJetsnackTheme.currentValue.typography val StyleScope.shapes: Shapes get() = JetsnackTheme.LocalJetsnackTheme.currentValue.shapes // Access CompositionLocals val button = Style { background(colors.brandSecondary) shape(shapes.small) }
Azione consigliata: crea uno stile per le modifiche ai valori del sottosistema
Ad esempio, se passi dalla modalità Buio alla modalità Luce e viceversa, esegui una query sui valori dei temi esistenti (tramite CompositionLocal) per modificare Style in modo dinamico:
// Do: Use CompositionLocals or themed values to create a single style val buttonStyle = Style { background(colors.brandSecondary) shape(shapes.small) }
Azione consigliata: sostituisci gli stili interi quando il componente differisce fondamentalmente tra le definizioni dei temi
Puoi sostituire interi oggetti di stile a livello di tema se si tratta di temi fondamentalmente diversi.
Ad esempio, se stai creando un'app con temi diversi per prodotto/pagina o offerta e molte proprietà di uno stile sono diverse, è accettabile sostituire interi set di stili a livello di tema.
// DO Switch out whole styles when many properties differ - if Product A and Product B are two white labelled apps that provide different Themes. val productBThemedButton = Style { shape(shapes.small) background(colors.brandSecondary) // other properties are fundamentally different } val productAThemedButton = Style { shape(shapes.large) background(colors.brand) // other properties are fundamentally different }