Una delle regole di Compose è che devi misurare i tuoi figli una sola volta; la misurazione di bambini e ragazzi due volte genera un'eccezione di runtime. Tuttavia, a volte ti servono alcune informazioni sui tuoi figli prima di misurarli.
Intrinsics ti consente di interrogare i bambini prima che vengano effettivamente misurati.
In un componibile, puoi richiederne intrinsicWidth
o intrinsicHeight
:
(min|max)IntrinsicWidth
: Data questa altezza, qual è la larghezza minima e massima con cui puoi colorare i tuoi contenuti?(min|max)IntrinsicHeight
: data questa larghezza, qual è l'altezza minima/massima con cui puoi colorare correttamente i tuoi contenuti?
Ad esempio, se chiedi il valore minIntrinsicHeight
di un Text
con width
infinito, restituirà il valore height
di Text
come se il testo fosse stato tracciato in una singola riga.
Funzioni intrinseche in azione
Immagina di voler creare un componibile che mostri due testi sullo schermo separati da un divisore come segue:
Come possiamo farlo? Possiamo avere un elemento Row
con due Text
all'interno che si espande il più possibile
e un Divider
al centro. Vogliamo che la Divider
sia alta
come la più alta Text
e sottile (width = 1.dp
).
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) Divider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
Se visualizziamo l'anteprima, vediamo che Divider
si espande a tutto lo schermo e non è ciò che vogliamo:
Questo accade perché Row
misura ogni asset secondario singolarmente e l'altezza di
Text
non può essere utilizzata per limitare il valore di Divider
. Vogliamo che Divider
riempia
lo spazio disponibile con una determinata altezza. In questo caso, possiamo usare il
modificatore height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
taglia i suoi figli costretti a raggiungere
l'altezza minima intrinseca. Poiché è ricorsiva, eseguirà una query su Row
e sui relativi elementi secondari minIntrinsicHeight
.
Applicarlo al nostro codice, funzionerà come previsto:
@Composable fun TwoTexts(modifier: Modifier = Modifier, text1: String, text2: String) { Row(modifier = modifier.height(IntrinsicSize.Min)) { Text( modifier = Modifier .weight(1f) .padding(start = 4.dp) .wrapContentWidth(Alignment.Start), text = text1 ) Divider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } } // @Preview @Composable fun TwoTextsPreview() { MaterialTheme { Surface { TwoTexts(text1 = "Hi", text2 = "there") } } }
Con anteprima:
Il valore minIntrinsicHeight
dell'elemento componibile Row
sarà il
minIntrinsicHeight
massimo dei relativi elementi secondari. Il valore minIntrinsicHeight
dell'elemento Divider
è 0 in quanto non occupa spazio se non vengono assegnati vincoli. Il valore minIntrinsicHeight
di Text
sarà quello del testo di un valore width
specifico. Di conseguenza, il vincolo height
dell'elemento Row
corrisponderà al valore massimo minIntrinsicHeight
dei Text
. Divider
espanderà quindi la sua height
al vincolo height
specificato dal Row
.
Funzionalità intrinseche nei layout personalizzati
Quando crei un modificatore Layout
o layout
personalizzato, le misurazioni intrinseche
vengono calcolate automaticamente in base alle approssimazioni. Di conseguenza, i calcoli potrebbero non essere corretti per tutti i layout. Queste API offrono opzioni
per eseguire l'override di questi valori predefiniti.
Per specificare le misurazioni intrinseche del tuo Layout
personalizzato,
esegui l'override di minIntrinsicWidth
, minIntrinsicHeight
, maxIntrinsicWidth
e maxIntrinsicHeight
dell'interfaccia
MeasurePolicy
durante la creazione.
@Composable fun MyCustomComposable( modifier: Modifier = Modifier, content: @Composable () -> Unit ) { Layout( content = content, modifier = modifier, measurePolicy = object : MeasurePolicy { override fun MeasureScope.measure( measurables: List<Measurable>, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurables: List<IntrinsicMeasurable>, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. } ) }
Quando crei il modificatore layout
personalizzato, sostituisci i metodi correlati nell'interfaccia di LayoutModifier
.
fun Modifier.myCustomModifier(/* ... */) = this then object : LayoutModifier { override fun MeasureScope.measure( measurable: Measurable, constraints: Constraints ): MeasureResult { // Measure and layout here // ... } override fun IntrinsicMeasureScope.minIntrinsicWidth( measurable: IntrinsicMeasurable, height: Int ): Int { // Logic here // ... } // Other intrinsics related methods have a default value, // you can override only the methods that you need. }
Consigliato per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Layout personalizzati {:#custom-layouts }
- Linee di allineamento in Jetpack Compose
- Fasi di Jetpack Compose