Compose 修飾子

修飾子を使用すると、コンポーザブルを装飾または拡張できます。修飾子では、次のようなことができます。

  • コンポーザブルのサイズ、レイアウト、動作、外観を変更する
  • ユーザー補助ラベルなどの情報を追加する
  • ユーザー入力を処理する
  • 要素をクリック可能、スクロール可能、ドラッグ可能、ズーム可能にするなど、高レベルの操作を追加する

修飾子は標準の Kotlin オブジェクトです。Modifier クラス関数のいずれかを呼び出して修飾子を作成します。

import androidx.compose.ui.Modifier

@Composable
private fun Greeting(name: String) {
  Column(modifier = Modifier.padding(24.dp)) {
    Text(text = "Hello,")
    Text(text = name)
  }
}

色付きの背景で、テキストの周囲にパディングを適用した 2 行のテキスト。

こうした関数を連鎖させてコンポーズできます。

@Composable
private fun Greeting(name: String) {
  Column(modifier = Modifier
    .padding(24.dp)
    .fillMaxWidth()
  ) {
    Text(text = "Hello,")
    Text(text = name)
  }
}

テキストの色付きの背景がデバイスの幅全体に拡張されている。

上記のコードでは、さまざまな修飾子関数を一緒に使用しています。

  • padding は、要素の周囲にスペースを挿入します。
  • fillMaxWidth は、コンポーザブルを親から与えられた最大幅に合わせて調整します。

おすすめの方法は、コンポーザブルのすべてmodifier パラメータを受け取り、その修飾子を UI を、UI を出力する最初の子に渡すようにすることです。これにより、コードの再利用性が向上し、動作が予測可能で直感的になります。詳しくは、Compose API のガイドライン「要素が修飾子パラメータを受け取って準拠する」についての説明をご覧ください。

修飾子の順序の重要性

修飾子関数の順序は重要です。各関数は前の関数が返す Modifier を変更するため、順序は最終結果に影響を与えます。次の例をご覧ください。

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .clickable(onClick = onClick)
            .padding(padding)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

エッジの周囲のパディングも含め、エリア全体がクリックに反応

上記のコードでは、padding 修飾子が clickable 修飾子の後に適用されるため、周囲のパディングを含むエリア全体がクリック可能となります。修飾子の順序が逆の場合、padding で追加されたスペースはユーザー入力に反応しません。

@Composable
fun ArtistCard(/*...*/) {
    val padding = 16.dp
    Column(
        Modifier
            .padding(padding)
            .clickable(onClick = onClick)
            .fillMaxWidth()
    ) {
        // rest of the implementation
    }
}

レイアウトのエッジ周囲のパディングがクリックに反応しない

組み込み修飾子

Jetpack Compose には、コンポーザブルの装飾や拡張に役立つ組み込み修飾子のリストが用意されています。レイアウトの調整に使用する一般的な修飾子は次のとおりです。

パディングとサイズ

Compose で提供されるレイアウトは、デフォルトでは子をラップしていますが、size 修飾子を使用してサイズを設定できます。

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(/*...*/)
        Column { /*...*/ }
    }
}

指定したサイズがレイアウトの親の制約を満たさない場合、そのサイズが適用されないことがあります。親の制約に関係なくコンポーザブルのサイズを固定する必要がある場合は、requiredSize 修飾子を使用します。

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.requiredSize(150.dp)
        )
        Column { /*...*/ }
    }
}

子の画像が親の制約よりも大きい

この例では、親 height100.dp に設定されていても、requiredSize 修飾子が優先されるため、Image の高さは 150.dp になっています。

親によって許可されているすべての高さを子レイアウトで埋めるには、fillMaxHeight 修飾子を追加します(Compose では、fillMaxSizefillMaxWidth も提供されています)。

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.size(width = 400.dp, height = 100.dp)
    ) {
        Image(
            /*...*/
            modifier = Modifier.fillMaxHeight()
        )
        Column { /*...*/ }
    }
}

画像の高さが親と同じ

要素全体にパディングを追加するには、padding 修飾子を設定します。

テキストのベースラインの上にパディングを追加して、レイアウトの上部からベースラインまで一定の距離を空ける場合は、paddingFromBaseline 修飾子を使用します。

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(
                text = artist.name,
                modifier = Modifier.paddingFromBaseline(top = 50.dp)
            )
            Text(artist.lastSeenOnline)
        }
    }
}

上にパディングが設定されたテキスト

オフセット

レイアウトを元の位置に対して相対的に配置するには、次のように offset 修飾子を追加し、x 軸と y 軸でオフセットを設定します。オフセットは、正の数でも負の数でもかまいません。paddingoffset の違いは、offset をコンポーザブルに追加しても測定値自体は変更されない点です。

@Composable
fun ArtistCard(artist: Artist) {
    Row(/*...*/) {
        Column {
            Text(artist.name)
            Text(
                text = artist.lastSeenOnline,
                modifier = Modifier.offset(x = 4.dp)
            )
        }
    }
}

親コンテナの右側に移動したテキスト

offset 修飾子は、レイアウト方向に従って横方向に適用されます。正の offset を設定する場合、左から右方向のコンテキストでは要素が右に移動し、右から左方向のコンテキストでは要素が左に移動します。レイアウト方向を考慮せずにオフセットを設定する必要がある場合は、absoluteOffset 修飾子をご覧ください。この修飾子を使用すると、正のオフセット値を設定した場合に要素が常に右へ移動します。

Compose での型の安全性

Compose には、特定のコンポーザブルの子に適用される場合にのみ動作する修飾子があります。たとえば、Box サイズに影響を与えずに子を親の Box と同じサイズにするには、matchParentSize 修飾子を使用します。

Compose では、カスタム スコープによってこの型の安全性が適用されます。たとえば、matchParentSizeBoxScope でのみ使用できます。そのため、この修飾子を使用できるのは Box 内で子が使用されている場合に限られます。

スコープ修飾子は、子に関して親が知っておくべき情報を親に通知します。これは、一般に親データ修飾子とも呼ばれます。その内部構造は汎用修飾子とは異なりますが、使用方法の観点から見るとこれらの違いは重要ではありません。

Box の matchParentSize

前述のように、Box サイズに影響を与えずに子レイアウトを親 Box と同じサイズにする場合は、matchParentSize 修飾子を使用します。

matchParentSizeBox スコープ内でしか使用できず、Box コンポーザブルの直接の子にのみ適用されます。

以下の例では、子 Spacer は親 Box からサイズを取得し、親はそのサイズを最も大きな子(この場合は ArtistCard)から取得しています。

@Composable
fun MatchParentSizeComposable() {
    Box {
        Spacer(Modifier.matchParentSize().background(Color.LightGray))
        ArtistCard()
    }
}

コンテナいっぱいに表示されたグレーの背景

matchParentSize ではなく fillMaxSize を使用した場合、Spacer は親が使用できるすべてのスペースを使用します。この場合、親は使用可能なスペース全体に拡大します。

画面全体に表示されたグレーの背景

行と列の比

前のセクションのパディングとサイズで説明したように、デフォルトでは、コンポーザブルのサイズは自身がラップするコンテンツによって定義されます。RowScopeColumnScope でのみ使用可能な weight 修飾子を使用すると、コンポーザブルのサイズを親の内部で柔軟に変動するように設定することもできます。

たとえば、2 つの Box コンポーザブルが含まれる Row があるとします。最初のボックスには、2 番目のボックスの 2 倍の weight が指定されているため、幅も 2 倍になります。Row の幅は 210.dp なので、最初の Box の幅は 140.dp、2 番目のボックスの幅は 70.dp になります。

@Composable
fun ArtistCard(/*...*/) {
    Row(
        modifier = Modifier.fillMaxWidth()
    ) {
        Image(
            /*...*/
            modifier = Modifier.weight(2f)
        )
        Column(
            modifier = Modifier.weight(1f)
        ) {
            /*...*/
        }
    }
}

画像の幅はテキストの 2 倍

詳細

修飾子の全リストと、各修飾子のパラメータとスコープを紹介します。