Compose のルールのひとつとして、子を 1 回しか測定できないことが挙げられます。子を 2 回測定した場合、ランタイム例外がスローされます。ただし、測定する前に子の情報が必要になる場合もあります。
Intrinsic を使用すると、実際に測定する前に子をクエリできます。
コンポーザブルに対して、次のように IntrinsicSize.Min または IntrinsicSize.Max を要求できます。
Modifier.width(IntrinsicSize.Min)- コンテンツを正しく表示するために必要な最小の幅はいくつですか?Modifier.width(IntrinsicSize.Max)- コンテンツを正しく表示するために必要な最大の幅はいくつですか?Modifier.height(IntrinsicSize.Min)- コンテンツを正しく表示するために必要な最小の高さはいくつですか?Modifier.height(IntrinsicSize.Max)- コンテンツを正しく表示するために必要な最大の高さはいくつでしょうか?
たとえば、カスタム レイアウトで width 制約が無限大の Text の minIntrinsicHeight を要求すると、テキストが 1 行で描画された Text の height が返されます。
Intrinsic の使い方
次のように、2 つのテキストを分割線で区切って画面上に表示するコンポーザブルを作成できます。
これを行うには、使用可能なスペースを埋める 2 つの Text コンポーザブルと中央の Divider を含む Row を使用します。Divider の高さは最も高い Text と同じにして、幅は狭くします(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 が画面全体に拡大されますが、これは望ましい動作ではありません。
これは、Row がそれぞれの子を個別に測定し、Text の高さを Divider の制約に使用できないためです。
代わりに Divider が指定の高さで空きスペースを埋めるようにするには、height(IntrinsicSize.Min) 修飾子を使用します。
height(IntrinsicSize.Min) は、子の高さが Intrinsic の最小の高さと同じになるようにサイズ設定します。この修飾子は再帰的であるため、Row とその子の minIntrinsicHeight をクエリします。
この修飾子をコードに適用すると、想定どおりに動作します。
@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") } } }
プレビュー:
Row の高さは次のように決定されます。
RowコンポーザブルのminIntrinsicHeightは、子の最大minIntrinsicHeightです。Divider要素のminIntrinsicHeightは、制約が設定されていない場合はスペースを占有しないため、0 になります。TextminIntrinsicHeightは、特定のwidthのテキストのものです。- したがって、
Row要素のheight制約が、Textの最大minIntrinsicHeightになります。 Dividerは自身のheightを、Rowで指定されたheight制約まで拡大します。
カスタム レイアウトでの Intrinsic
カスタムの Layout 修飾子または layout 修飾子を作成すると、近似値に基づいて固有の測定値が自動的に計算されます。このため、すべてのレイアウトで計算が不正確になる場合があります。これらの API には、こうしたデフォルト値をオーバーライドするオプションが用意されています。
カスタム Layout の組み込み測定値を指定するには、作成時に MeasurePolicy インターフェースの minIntrinsicWidth、minIntrinsicHeight、maxIntrinsicWidth、maxIntrinsicHeight をオーバーライドします。
@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. } ) }
カスタムの layout 修飾子を作成する場合は、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. }
あなたへのおすすめ
- 注: JavaScript がオフになっている場合はリンクテキストが表示されます
- カスタム レイアウト {:#custom-layouts}
- Jetpack Compose でのアライメント ライン
- Jetpack Compose のフェーズ