geDemのアバターアイコン
geDem
 Blog
記事のカバー写真

Jetpack ComposeでButtonの自動パディングを消す方法

geDemのアバターアイコン
geDem
ペン

原因としては、3つ考えられます。

  • ContentPadding を指定していない
  • Buttonのサイズが48dp未満
  • Buttonの中にあるコンポーザブルが58dp未満

ContentPaddingを指定していない

問題のあるコード

自動余白がついたボタン

SampleView.kt@Composable
fun SampleView(modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Button(
            modifier = Modifier,
            onClick = { /*TODO*/ },
        ) {
            Box(Modifier.size(60.dp), contentAlignment = Alignment.Center) {
                Text(
                    text = "サンプルボタン"
                )
            }
        }
    }
}

原因と解決策

ここでの余白の原因は、Buttonの引数である、contentPaddingを指定していないことです。

contentPaddingを指定しないと、デザインがいい感じになるために、デフォルトで横に24dp,縦に8dp入れてくれています。😠

Button.ktpublic fun Button(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    shape: Shape = ButtonDefaults.shape,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    elevation: ButtonElevation? = ButtonDefaults.buttonElevation(),
    border: BorderStroke? = null,
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding, // ←原因!!!!
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    content: @Composable() (RowScope.() -> Unit)
):

しかし、基本的に邪魔なことが多いのでButton実装する時はいつも0dp指定する、で問題ないと思います。

SampleView.kt@Composable
fun SampleView(modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Button(
            modifier = Modifier,
            onClick = { /*TODO*/ },
            contentPadding = PaddingValues(0.dp) // 追加!!!!
        ) {
            Box(Modifier.size(60.dp), contentAlignment = Alignment.Center) {
                Text(
                    text = "サンプルボタン"
                )
            }
        }
    }
}

自動余白がないボタン

ボタンのサイズが48dp未満

contentPaddingを0にしても、自動でパディングが付いてしまうことがあります。

問題のあるコード

自動余白がついた画像

SampleView.kt@Composable
fun SampleView(modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Button(
            modifier = Modifier,
            onClick = { /*TODO*/ },
            contentPadding = PaddingValues(0.dp) // 追加!!!!
        ) {
            Box(Modifier.size(30.dp), contentAlignment = Alignment.Center) {
                Text(
                    text = "サンプル"
                )
            }
        }
    }
}

size(30dp)を指定しているのに丸いですね🤔

原因と解決策

原因としては、Jetpack Composeでは、インテラクション(タップとか)可能なコンポーザブルが、48dp48dpではない場合、自動的に48dp48dpになるように余白をつけるからです。😠

参考: タップターゲットのサイズ


解決策として、LocalMinimumTouchTargetEnforcementコンポジションというものを使用する方法もありますが、公式は勧めていないので、使わないようにしましょう。

参考: Compose Material

ではどうするのかというと、Button自体にサイズを指定します。

SampleView.kt@Composable
fun SampleView(modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Button(
            modifier = Modifier
                .size(30.dp), // 追加!!!!
            onClick = { /*TODO*/ },
            contentPadding = PaddingValues(0.dp)
        ) {
            Box(Modifier.size(30.dp), contentAlignment = Alignment.Center) {
                Text(
                    text = "サンプル"
                )
            }
        }
    }
}

Buttonの中にあるコンポーザブルが幅58dp未満or高さ40dp未満

contentPaddingを0にして、Buttonの中身のサイズを48dp以上だったとしても、余白が付いてしまうことがあります。(Button自体のサイズを指定すれば問題ないですが)

問題のあるコード

↓ 若干ボタンの右に余白がついているのが分かりますかね・・?

自動余白がついたボタン

@Composable
fun SampleView(modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Button(
            modifier = Modifier,
            onClick = { /*TODO*/ },
            contentPadding = PaddingValues(0.dp)
        ) {
            Box(Modifier.size(50.dp), contentAlignment = Alignment.Center) {
                Text(text = "サ")
            }
        }
    }
}

原因と解決策

原因は、Buttonコンポーザブルにデフォルトで指定されている、最小サイズの指定です。😠

Button.ktRow(
    Modifier
        .defaultMinSize(
            minWidth = ButtonDefaults.MinWidth, // ← 原因!!!!
            minHeight = ButtonDefaults.MinHeight // ← 原因!!!!
        )
        .padding(contentPadding),
    horizontalArrangement = Arrangement.Center,
    verticalAlignment = Alignment.CenterVertically,
    content = content
)

MinWidth→58dp, MinHeight→40dp

defaultMinSizeモディファイアは、制約としては一番弱く、他のminSizeモディファイアが指定されていない時に適用されるものです。

なので、ButtonモディファイアにminSizeの上書きをしてあげれば解決します。

Button.ktRow(
    Modifier
        .defaultMinSize(
            minWidth = ButtonDefaults.MinWidth, // ← 原因!!!!
            minHeight = ButtonDefaults.MinHeight // ← 原因!!!!
        )
        .padding(contentPadding),
    horizontalArrangement = Arrangement.Center,
    verticalAlignment = Alignment.CenterVertically,
    content = content
)
SampleView.kt@Composable
fun SampleView(modifier: Modifier = Modifier) {
    Column(modifier = modifier) {
        Button(
            modifier = Modifier
                .sizeIn(minWidth = 50.dp, minHeight = 50.dp), // 追加!!!!
            onClick = { /*TODO*/ },
            contentPadding = PaddingValues(0.dp)
        ) {
            Box(Modifier.size(50.dp), contentAlignment = Alignment.Center) {
                Text(text = "サ")
            }
        }
    }
}

自動余白がついていないボタン



Buttonには、こういった直感的でない仕様が入っているので、個人的には、タップ可能なコンポーネントを作る際、Surfaceとかclickableを使って自分でボタンを作るのが好みです。

🙂‍↕️最後まで読んでいただきありがとうございます🙂‍↕️