Jetpack Composeには Shape
というのがあり、これを使って、画像を切り抜いたり、背景色を塗ったり、ボーダーを描いたりすることができます。
Compose側では CircleShape
, RoundedCornerShape
, CutCornerShape
などが定義されていますので、基本的なものはこれらで対応可能になっています。
もし、定義されていないShapeを使用したい場合は、自分でカスタムのShapeも実装することが可能です。
カスタムShapeの実装
カスタムShapeを実装するには、 GenericShape
を使うことで簡単に実装することができます。
val CustomShape = GenericShape { size, layoutDirection ->
// 三角形の頂点へ移動
moveTo(size.width / 2f, 0f)
// 頂点から右下に向かって線を引く
lineTo(size.width, size.height)
// 右下から左に向かって線を引く
lineTo(0f, size.height)
// GenericShapeのほうで close() が呼ばれるので、最後に線が頂点で閉じる
}
コンストラクタで Path
をレシーバーにしたbuilderを渡すことができるようになっています。このbuilderの中でPathを組み立てることでカスタムのShapeを実装することができます。
この例では三角形のカスタムShapeを実装しています。 コメントに何をやってるか簡単に書いておきました。
このカスタムShapeを使う場合は特別なことは特に不要で、通常通り使用するだけで大丈夫です。
Image(
painter = painterResource(R.drawable.sample),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(200.dp)
.clip(CustomShape) // 作成したカスタムShapeで切り抜く
)
これを実行すると以下のように、作成したカスタムShapeで画像が切り抜かれます。
別の方法としては、 Shape
を直接実装する方法もあります。こちらは
class CustomShape : Shape {
override fun createOutline(
size: Size,
layoutDirection: LayoutDirection,
density: Density
): Outline {
val path = Path().apply {
moveTo(size.width / 2f, 0f)
lineTo(size.width, size.height)
lineTo(0f, size.height)
close()
}
return Outline.Generic(path)
}
}
先程と同じShapeを実装しています。 createOutline
メソッドを実装して、 Outline
を返却する感じになります。 今回はカスタムのPathを使いたいので Outline.Generic
を使っています。
使用する場合は、先程とほぼ同じですが、classなのでインスタンスを作成する必要があります。
Image(
painter = painterResource(R.drawable.sample),
contentDescription = null,
contentScale = ContentScale.Crop,
modifier = Modifier
.size(200.dp)
.clip(CustomShape()) // インスタンスの作成が必要
)
GenericShape vs Shape
カスタムShapeを実装する方法を2つ紹介しましたが、どちらが良いかはパラメータによって形を変えるかどうかによります。
GenericShape
ではパラメータを外部から受け取ることができないので毎回決まった形になります。もし、何かパラメータを受け取って形を変えたい場合は Shape
を直接実装してコンストラクタでパラメータを受け取ると良いと思います。
Shape
を使ったときの実装ですが、1点注意があって、 equals
が実装されていないので、Recompositionがskipされなくなります。なので、自分で equals
を実装する必要があります。このあたりは 既存の実装 などを参考にしてみると良いと思います。GenericShape
に関しては実装されてるので、自分で実装する必要はないです。