Una delle regole di Compose è che i figli devono essere misurati una sola volta; misurare i figli due volte genera un'eccezione di runtime. Tuttavia, a volte hai bisogno di alcune informazioni sui tuoi figli prima di misurarli.
Gli intrinseci ti consentono di eseguire query sui bambini prima che vengano effettivamente misurati.
Per un componente componibile, puoi chiedere il IntrinsicSize.Min
o il IntrinsicSize.Max
:
Modifier.width(IntrinsicSize.Min)
- Qual è la larghezza minima necessaria per visualizzare correttamente i tuoi contenuti?Modifier.width(IntrinsicSize.Max)
- Qual è la larghezza massima necessaria per visualizzare correttamente i contenuti?Modifier.height(IntrinsicSize.Min)
- Qual è l'altezza minima necessaria per visualizzare correttamente i contenuti?Modifier.height(IntrinsicSize.Max)
- Qual è l'altezza massima necessaria per visualizzare correttamente i tuoi contenuti?
Ad esempio, se chiedi l'minIntrinsicHeight
di un Text
con vincoli di width
infiniti in un layout personalizzato, verrà restituito l'height
del Text
con il testo disegnato su una sola riga.
Funzioni intrinseche in azione
Supponiamo di voler creare un composable che mostri due testi sullo schermo separati da un divisore come questo:
Come possiamo farlo? Possiamo avere un Row
con due Text
all'interno che si espandono il più possibile e un Divider
al centro. Vogliamo che Divider
sia alto
come 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 ) VerticalDivider( 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 è quello che vogliamo:
Ciò accade perché Row
misura ogni bambino singolarmente e l'altezza di
Text
non può essere utilizzata per vincolare Divider
. Vogliamo che il Divider
riempia
lo spazio disponibile con un'altezza specifica. A questo scopo, possiamo utilizzare il modificatore
height(IntrinsicSize.Min)
.
height(IntrinsicSize.Min)
dimensiona i relativi elementi secondari in modo che siano alti almeno quanto la loro altezza intrinseca minima. Poiché è ricorsiva, eseguirà una query su Row
e sui relativi
elementi secondari minIntrinsicHeight
.
Se applichiamo questa logica 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 ) VerticalDivider( 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:
L'minIntrinsicHeight
del composable Row
sarà il massimo
minIntrinsicHeight
dei suoi elementi secondari. L'minIntrinsicHeight
dell'elemento Divider
è 0 perché non occupa spazio se non vengono forniti vincoli; l'minIntrinsicHeight
di Text
sarà quello del testo dato un width
specifico. Pertanto, il vincolo height
dell'elemento Row
sarà il massimo
minIntrinsicHeight
degli Text
. Divider
espanderà quindi il suo height
fino al vincolo height
fornito da Row
.
Intrinseci nei layout personalizzati
Quando crei un modificatore Layout
o layout
personalizzato, le misurazioni intrinseche
vengono calcolate automaticamente in base alle approssimazioni. Pertanto, i calcoli potrebbero non essere corretti per tutti i layout. Queste API offrono opzioni
per ignorare 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, esegui l'override dei 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