Jetpack ComposeでonClickのrippleエフェクトを止めたい

この記事をシェア
JetpackCompose一問一答

Jetpack ComposeのModifier.clickableを使うと自動的にリップルエフェクト(タップした点から波紋が広がるようなエフェクト)が有効になります。今回はこのリップルエフェクトを無効にする方法を紹介します。

やりたいこと

こんな感じで、リップルエフェクトを無効にします。

サンプル

ソースコードはGitHubにあります。

主な環境は以下の通りです。

  • Kotlin 1.7210
  • Compose Compiler 1.3.2
  • Compose Libraries 1.2.1
  • Material3 1.0.0-rc01
  • Accompanist 0.25.1

二つのModifier.clickable

標準のclickableには引数が少ないバージョン引数が多いバージョンがあります。

fun Modifier.clickable(
    enabled: Boolean = true,
    onClickLabel: String? = null,
    role: Role? = null,
    onClick: () -> Unit
): Modifier
fun Modifier.clickable(
    interactionSource: MutableInteractionSource,
    indication: Indication?,
    enabled: Boolean = true,
    onClickLabel: String? = null,
    role: Role? = null,
    onClick: () -> Unit
): Modifier

シンプルにModifier.clickable { ... }という書き方をした時に呼び出されるのは、引数が少ない方です。引数が少ない方のclickableは、内部で引数が多い方を呼び出します。その時にindicationLocalIndicationを渡しているので、デフォルトではリップルエフェクトが発生します。

リップルエフェクトを無効にするには、引数が多い方のclickableindication = nullを指定すればOKです。interactionSourceにはremember { MutableInteractionSource() }を指定するのが定型です。

Modifier.clickable(
    interactionSource = remember { MutableInteractionSource() },
    indication = null,
) {
    // onClickの処理
}

Modifierの拡張関数を作る

以下のようにModifierの拡張関数を作っておくと、使いまわせて便利です。

fun Modifier.clickableNoRipple(
    enabled: Boolean = true,
    onClickLabel: String? = null,
    role: Role? = null,
    onClick: () -> Unit,
): Modifier = composed {
    this.clickable(
        interactionSource = remember { MutableInteractionSource() },
        indication = null,
        enabled = enabled,
        onClickLabel = onClickLabel,
        role = role,
        onClick = onClick
    )
}

ポイントは、composedです。Developer Guideには以下のように説明されています。

変更する要素ごとに、コンポーズされる Modifier のジャストインタイム コンポジションを宣言します。

https://developer.android.com/jetpack/compose/modifiers-list?hl=ja

ちょっと日本語が難しいですが、、、要するに、状態を持つModifierを複数個所で同時に使っても問題ないようにしてくれる、ということだと思います。今回の場合はremember { MutableInteractionSource() }の部分が状態(ステートフル)ですね。

サンプルソース

冒頭の動画のサンプルソースはこんな感じです。一つ目のコンポーザブルには、標準の引数が少ない方のclickableを使っているので、リップルエフェクトが発生します。二つ目のコンポーザブルには、先ほど作ったclickableNoRippleを使っているので、リップルエフェクトが無効になります。

@Composable
fun NoRippleEffectSample() {
    Column(
        ...
    ) {
        var text1 by remember { mutableStateOf("Click me") }
        var text2 by remember { mutableStateOf("Click me") }
        ClickMe(
            title = text1,
            subTitle = "(Ripple effect)",
            color = MaterialTheme.colorScheme.secondary,
            modifier = Modifier.clickable { text1 += "!" }
        )
        ClickMe(
            title = text2,
            subTitle = "(No ripple effect)",
            color = MaterialTheme.colorScheme.tertiary,
            modifier = Modifier.clickableNoRipple { text2 += "!" }
        )
    }
}

ClickMeの中身なども含めてソースコードを見たい方は、GitHubを参照してください。

JetpackCompose一問一答

Jetpack Compose一問一答

コンテンツは随時追加していきます。

この記事をシェア