LoginSignup
12
7

More than 1 year has passed since last update.

Jetpack ComposeになってShapeがすごく簡単になった

Posted at

Jetpack Composeになって、Viewの形状を変えるShape周りがすごく使いやすくなってました。
社内のLT会でした内容をQiitaにもまとめようと思います。

今までのAndroid Viewでは

例えばこういう形状のタグ的なものを作ろうと思ったとき、shapeのxmlリソースを用意してbackgroundに当てる必要がありました。

unnamed.png

shape_tag_background.xml
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
  android:shape="rectangle">

  <corners android:radius="16dp" />
  <padding
    android:bottom="0dp"
    android:left="0dp"
    android:right="0dp"
    android:top="0dp" />
  <stroke
    android:width="1dp"
    android:color="@color/blue" />
</shape>

Viewの形状を変えるというよりかは、背景のリソースを用意して配置するような感じでした。
正直これはかなり面倒でしたし、XMLのタグを覚えていないので毎回ググったり他から引用したりしてます。

微妙にradiusの値が違うとか、ボーダーの太さが違うとか、色が違うというだけで別名のxmlリソースを用意する必要が発生したりして、普通にViewに対してプロパティでほしい。。と何度も思ったことです(笑)

Jetpack Compose Default Shape

対してJetpack Composeでは、このshapeがとっても簡単に、扱いやすくなっていました。宣言的UIなのでもちろんxmlを用意する必要はありません。

デフォルトで用意されているshapeは、 RectangleShape CircleShape RoundedCornerShape CutCornerShape の4つです。

一番上の正四角形はこんな感じのコードになっています。

@Composable
fun Rectangle() {
    Box(
        modifier = Modifier
            .size(100.dp)
            .clip(RectangleShape)
            .background(LightGray)
    )
}

Boxのmodifierにshapeを指定しています。Android Viewのときはbackgroundに指定していましたが、clip() に指定しています。Boxをこのshapeでくり抜いてねってことですね。
shape用のmodifierが追加されているので、背景色やボーダーの色など、形状に関係のない項目に依存しなくなりました👏

widthを長く指定すれば、検索ボックス的なものの背景も簡単に作れそうですね💡

Rotate

Shapeではないのですが、Jetpack Composeでは回転(rotate)も簡単です。これに関してはAndroid ViewのほうでもViewのプロパティにあるみたいですね。

@Composable
fun RoundedCorner(modifier: Modifier = Modifier) {
    Box(
        modifier = modifier
            .size(100.dp)
            .clip(RoundedCornerShape(10.dp))
            .background(LightGray)
    )
}

@Composable
fun RotatedRoundedCorner() {
    RoundedCorner(modifier = Modifier.rotate(25f))
}

Custom Shape

デフォルトで用意されている形状とは違う形状を用意したい場合はCustom Shapeを作る必要があります。こういうCustom系のものって苦手なんですがShapeのはそう難しくなかったです(複雑な場合は別)

例えば三角形を作りたい場合はこんな感じのようです。

@Composable
fun Triangle(modifier: Modifier = Modifier) {
    val triangleShape = GenericShape { size, _ ->
        moveTo(size.width / 2f, 0f)
        lineTo(size.width, size.height)
        lineTo(0f, size.height)
    }

    Box(
        modifier = modifier
            .size(100.dp)
            .clip(triangleShape)
            .background(LightGray)
    )
}

GenericShape を使って自作のShapeを定義してあげてます。moveTo(x, y)lineTo(x, y) を使って形状を描いてあげるイメージです。

もう一例として、付箋のようなちょっと複雑な形状も作れます。

@Composable
fun CustomCutCorner() {
    val shape = GenericShape { size, _ ->
        lineTo(size.width, 0f)
        val cutSize = size.height / 4
        lineTo(size.width, size.height - cutSize)
        lineTo(size.width - cutSize, size.height)
        lineTo(0f, size.height)
    }

    Box(
        modifier = Modifier
            .width(90.dp)
            .height(100.dp)
            .clip(shape)
            .background(LightGray)
    )
}

コードだとイメージが付きづらいと思いますが、流れはこんな感じです。理解してしまえば、わりと応用できそう。
でも曲線が混じってくると難しそうな印象です😅

custom_shape.jpg

最初のタグの例を実装してみる

最後に、最初に挙げたタグっぽいViewをJetpack Composeで実装してみます。

@Composable
fun BorderTag(modifier: Modifier = Modifier) {
  val blue = Color(0xFF07bac6)
  Box(
    contentAlignment = Alignment.Center,
    modifier = modifier
        .height(34.dp)
        .border(width = 1.dp, shape = CircleShape, color = blue)
    ) {
      Text(
        text = "リラックス",
        color = blue,
        fontSize = 14.sp,
        modifier = Modifier.padding(horizontal = 16.dp)
      )
    }
  )
}

unnamed.png

ボーダーの部分はBoxで実装しています。その中にTextViewを配置しています。
ボーダーの描画と形状指定はBoxのmodifierで実装していて、Modifier.border を使っています。ボーダーちゃんと用意されてるの嬉しいですよね:joy:

最初から最後までコードなのでXMLのタグ調べる必要もないですし、動的に操作する必要があったとしても悩まずに実装できそうです:heart_eyes:

12
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
7