Una delle regole di Compose è che devi misurare i bambini una sola volta; la misurazione dei bambini due volte genera un'eccezione di runtime. Tuttavia, a volte hai bisogno di alcune informazioni sui tuoi figli prima di misurarli.
Intrinsics ti consente di eseguire query sui bambini prima che vengano effettivamente misurati.
A un composable puoi chiedere il intrinsicWidth
o il intrinsicHeight
:
(min|max)IntrinsicWidth
: data questa larghezza, qual è la larghezza minima/massima con cui puoi dipingere correttamente i tuoi contenuti?(min|max)IntrinsicHeight
: data questa altezza, qual è l'altezza minima/massima con cui puoi dipingere correttamente i tuoi contenuti?
Ad esempio, se chiedi il minIntrinsicHeight
di un Text
con height
infinito, verrà restituito il height
del Text
come se il testo fosse stato disegnato in una singola riga.
Funzioni intrinseche in azione
Immaginiamo di voler creare un composable che mostri sullo schermo due testi separati da un divisore come questo:
Come possiamo farlo? Possiamo avere un Row
con due Text
al suo interno che si espandono il più possibile e un Divider
al centro. Vogliamo che Divider
sia alto quanto il Text
più alto 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 ) HorizontalDivider( color = Color.Black, modifier = Modifier.fillMaxHeight().width(1.dp) ) Text( modifier = Modifier .weight(1f) .padding(end = 4.dp) .wrapContentWidth(Alignment.End), text = text2 ) } }
Se ne vediamo l'anteprima, vediamo che Divider
si espande per l'intero schermo e
non è quello che vogliamo:
Questo accade perché Row
misura ogni bambino singolarmente e l'altezza diText
non può essere utilizzata per limitare Divider
. Vogliamo che Divider
riempia
lo spazio disponibile con un'altezza specifica. A questo scopo, possiamo utilizzare il modificatore height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
assegna alle sue figlie tag di taglia che le costringono ad avere un'altezza pari alla loro altezza minima intrinseca. Poiché è ricorsiva, eseguirà una query su Row
e sui suoi figli minIntrinsicHeight
.
Se applichiamo questo 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 ) HorizontalDivider( 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 minIntrinsicHeight
del composable Row
sarà il valore minIntrinsicHeight
massimo dei suoi elementi secondari. Il valore minIntrinsicHeight
dell'elemento Divider
è 0 perché non occupa spazio se non vengono specificati vincoli. Il valore minIntrinsicHeight
di Text
sarà quello del testo a cui è stato assegnato un valore width
specifico. Pertanto, la limitazione height
dell'elemento Row
sarà il valore minIntrinsicHeight
massimo dei valori Text
. Divider
espanderà quindi il proprio height
fino al vincolo height
dato da Row
.
Elementi intrinseci nei layout personalizzati
Quando crei un modificatore Layout
o layout
personalizzato, le misurazioni intrinseche vengono calcolate automaticamente in base ad approssimazioni. Pertanto, i calcoli potrebbero non essere corretti per tutti i layout. Queste API offrono opzioni per eseguire l'override di queste impostazioni predefinite.
Per specificare le misurazioni intrinseche del Layout
personalizzato, override 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 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. }
Consigliati 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