初めに
ポート株式会社 サービス開発部 Advent Calendar 2023 22日目の記事です。
今回は、細かいところではありますが、CornerSize
の指定方法の違いと注意することについて、解説していきます。
公式ドキュメントのandroidx.compose.foundation.shape
に書かれている内容がほとんどなので、こちらを参考にしてください。
結論
最初に、僕が伝えたいことを述べたいと思います。
これから解説するCornerSize
には、指定方法がいくつもあるので、どんな端末でもデザインを崩さないように、適切な指定方法を選んでいきましょう。
きっかけ
自分が携わっているプロジェクトでは、Button
やChip
、Card
などの多くのコンポーネントを角丸にしています。
アプリの動作確認を、複数端末で見比べながら行っていた時、ある端末ではデザイン通りのUIになっていましたが、別の端末ではデザイン崩れを起こしているのを見つけました。
この修正作業を行った際に、CornerSize
の仕様について調べたというのがきっかけです。
Shape
まず、AndroidにはShape
があり、このクラスを指定するとコンポーネントの形が変化します。
AbsoluteCutCornerShape, CutCornerShape
角が削られた形を生成するクラスです。
AbsoluteCutCornerShape
とCutCornerShape
の違いは、右から左へのレイアウト方向(LayoutDirection.Rtl
)のCornerSize
が考慮されているかどうかです。
4方向の角を指定するHelperメソッドを見てみるとわかりやすいです。
- https://developer.android.com/reference/kotlin/androidx/compose/foundation/shape/package-summary#AbsoluteCutCornerShape(androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp)
- https://developer.android.com/reference/kotlin/androidx/compose/foundation/shape/package-summary#CutCornerShape(androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp,androidx.compose.ui.unit.Dp)
// left・rightの関係
fun AbsoluteCutCornerShape(
topLeft: Dp = 0.dp,
topRight: Dp = 0.dp,
bottomRight: Dp = 0.dp,
bottomLeft: Dp = 0.dp
): AbsoluteCutCornerShape
// start・endの関係
fun CutCornerShape(
topStart: Dp = 0.dp,
topEnd: Dp = 0.dp,
bottomEnd: Dp = 0.dp,
bottomStart: Dp = 0.dp
): CutCornerShape
AbsoluteRoundedCornerShape, RoundedCornerShape
角が丸くした形を生成するクラスです。
CutCornerShape
と同様、AbsoluteRoundedCornerShape
とRoundedCornerShape
の違いは、右から左へのレイアウト方向のCornerSize
が考慮されているかどうかです。
CircleShape
RoundedCornerShape
の一種で、円形に生成するクラスです。
CircleShape
は、RoundedCornerShape(50)
と同義になります。
CircleShape == RoundedCornerShape(50)
GenericShape
Path
を使用して、独自に形を生成することもできます。
例:台形
GenericShape { size, _ ->
// 始点
moveTo(size.width * 1 / 3, 0f)
// 台形になるように線を引く
lineTo(size.width * 2 / 3, 0f)
lineTo(size.width, size.height)
lineTo(0f, size.height)
lineTo(size.width * 1 / 3, 0f)
}
CornerSize指定
(ここから本題です。)
Composeであらかじめ用意されているShape
(CutCornerShape
、RoundedCornerShape
)には、上述のようなHelperメソッドが用意されていて、そのメソッドを使用することでShape
を生成します。
今回は、RoundedCornerShape
を見ていきます。
fun RoundedCornerShape(corner: CornerSize): RoundedCornerShape
fun RoundedCornerShape(percent: Int): RoundedCornerShape
fun RoundedCornerShape(size: Dp): RoundedCornerShape
fun RoundedCornerShape(size: Float): RoundedCornerShape
fun RoundedCornerShape(
topStart: Dp = 0.dp,
topEnd: Dp = 0.dp,
bottomEnd: Dp = 0.dp,
bottomStart: Dp = 0.dp
): RoundedCornerShape
fun RoundedCornerShape(
topStart: Float = 0.0f,
topEnd: Float = 0.0f,
bottomEnd: Float = 0.0f,
bottomStart: Float = 0.0f
): RoundedCornerShape
fun RoundedCornerShape(
topStartPercent: @IntRange(from = 0, to = 100) Int = 0,
topEndPercent: @IntRange(from = 0, to = 100) Int = 0,
bottomEndPercent: @IntRange(from = 0, to = 100) Int = 0,
bottomStartPercent: @IntRange(from = 0, to = 100) Int = 0
): RoundedCornerShape
上記で挙げたメソッドは全て、引数の値をCornerSize
に変換し、RoundedCornerShape
に渡しています。
CornerSize
の指定方法
CornerSize
に変換する場合は、以下のメソッドを使用しています。
fun CornerSize(percent: @IntRange(from = 0, to = 100) Int): CornerSize
fun CornerSize(size: Dp): CornerSize
fun CornerSize(size: Float): CornerSize
3つの指定方法があり、おおまかに割合 or サイズ(絶対値) で指定します。
割合
0 ~ 100のIntを指定することで、コンポーネントサイズに対しての指定した割合で角サイズを決定します。
0よりも小さい場合または100よりも大きい場合は、エラーになります。
サイズ(絶対値)
サイズは、dp
とpx
の2つの指定方法があります。
androidx.compose.ui.unit.Dp
を渡すとdp
指定、Float
を渡すとpx
指定になり、固定値で角サイズを決定します。
注意すること
「CornerSize
の指定方法」でお気づきになるかもしれないですが、CornerSize
を指定する時、Int
とFloat
で意味合いが違います。(当然ですね。。。)
多くの場合は、割合 == Float
のイメージだと思っているので、割合で指定したい時にFloat
で渡しがちになります。(自分はそう思ってました。)
しかし、Float
で渡してしまうと、px
指定になってしまうため、デバイス密度に依存してしまいます。
そのため、特定のデバイスではデザイン通りになっていても、他のデバイスでは角サイズが足りていないという現象が起きてしまいます。
例: CornerSize
を50f
で指定する。
Pixel 7 Pro | Pixle 6a |
---|---|
終わりに
このように、端末によってデザインが変わってしまうのは、デザインを作成したデザイナーさんも意図していないことが多いので、どんな端末でもデザインを崩さないように、適切な指定方法を行うことを意識していきましょう!
今回の僕の場合では、UIテストを端末ごと(特にDpiが違う端末)で行い、デザインが正しいかをチェックすることを担保することでも回避できることなので、ComposeでのUIテストもちゃんと学んできたいなとおもえる出来事だったと思います。
参考
今回、参考にしていただいた記事です。