Una delle regole di Compose è che devi misurare i componenti secondari una sola volta; la misurazione dei componenti secondari due volte genera un'eccezione di runtime. Tuttavia, a volte è necessario avere alcune informazioni sui figli prima di misurarli.
Le funzioni intrinseche ti consentono di eseguire query sugli elementi secondari prima che vengano effettivamente misurati.
A un composable, puoi chiedere il suo IntrinsicSize.Min o IntrinsicSize.Max:
Modifier.width(IntrinsicSize.Min): qual è la larghezza minima necessaria per visualizzare correttamente i 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 contenuti?
Ad esempio, se chiedi la minIntrinsicHeight di un Text con vincoli width infiniti in un layout personalizzato, viene restituita la height del Text con il testo disegnato in una singola riga.
Intrinsics in azione
Puoi creare un componibile che mostri due testi sullo schermo separati da un divisore:
Per farlo, utilizza un Row con due componibili Text che riempiono lo spazio disponibile e un Divider al centro. Divider deve essere alto quanto l'Text più alto e deve essere 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 ) } }
Divider si espande a schermo intero, il che non è il comportamento desiderato:
Questo accade perché Row misura ogni elemento secondario singolarmente e l'altezza di Text non può essere utilizzata per vincolare Divider.
Per fare in modo che Divider riempia lo spazio disponibile con un'altezza specifica, utilizza invece il modificatore height(IntrinsicSize.Min).
height(IntrinsicSize.Min) dimensiona i suoi elementi secondari in modo che siano alti quanto la loro altezza intrinseca minima. Poiché questo modificatore è ricorsivo, esegue una query sul
minIntrinsicHeight di Row e dei relativi elementi secondari.
L'applicazione di questo modificatore al codice lo fa funzionare 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'altezza di Row viene determinata nel seguente modo:
- La
minIntrinsicHeightdel composableRowè laminIntrinsicHeightmassima dei suoi elementi secondari. - La proprietà
minIntrinsicHeightdell'elementoDividerè 0, in quanto non occupa spazio se non vengono forniti vincoli. - La
TextminIntrinsicHeightè quella del testo per unwidthspecifico. - Pertanto, il vincolo
heightdell'elementoRowdiventa il valore massimominIntrinsicHeightdeiText. Dividerespande quindi il proprioheightal vincoloheightfornito daRow.
Intrinsics 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 eseguire l'override di queste impostazioni predefinite.
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