Viewに角丸をつける方法は様々あります。
以下のように、複雑なレイアウトを角丸に切り取って表示する方法を紹介します。
Layout | 角丸化 |
---|---|
![]() |
![]() |
ViewGroupを継承してdraw処理をoverrideしてしまえば何でもありになります。
ただ、手間も大きいため、これ以外の方法を考えてみます。
CardViewで囲む
お手軽な方法としてはこれですね。CardViewはこのような角丸なViewを作るためのViewなので、以下のように指定して、角丸にしたいレイアウト全体を囲めば最初の例にあるような角丸をつけることができます。
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:cardCornerRadius="200dp"
app:cardElevation="0dp"
>
...
</androidx.cardview.widget.CardView>
デメリットとしてはViewの階層が余分に一つ必要になるところでしょうか?
background + clipToOutline を使う
xmlでshapeを定義するGradientGrawableを設定し、clipToOutlineを設定することでも角丸にできます。
例えば、以下のように角丸を設定したGradientDrawableを定義し、
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners android:radius="200dp" />
<solid android:color="#00FF00" />
</shape>
以下のようにbackgroundとしてこのdrawableを指定、android:clipToOutline="true"
を設定します。
xmlでclipToOutlineを設定できるのはAPI 31以上です。
かなり新しい環境でしか使えませんが、コード上から指定する方法であれば、API 21から使えますので、clipToOutline = true
を設定することでほとんどの環境で使える方法です。
<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/round"
android:clipToOutline="true"
android:orientation="vertical"
/>
これで背景に設定したDrawableのshapeに併せて全体がclipされ、角丸表示となります。
clip処理に必要なのはshapeの情報だけですので、背景の指定が必要ない場合は、solid
タグのない、GradientDrawableを指定することで、その形状に切り取って表示できます。
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
>
<corners android:radius="200dp" />
</shape>
デメリットとしてはbackgroundにshapeを指定する必要があるため、別のbackgroundを指定したい場合は別のViewで囲むなどが必要になるところでしょうか?
ViewOutlineProvider + clipToOutline を使う
前項の方法は内部実装としてBackgroundDrawableをベースとしたViewOutlineProviderが使われています。
public static final ViewOutlineProvider BACKGROUND = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
Drawable background = view.getBackground();
if (background != null) {
background.getOutline(outline);
} else {
outline.setRect(0, 0, view.getWidth(), view.getHeight());
outline.setAlpha(0.0f);
}
}
};
Backgroundとは別に独立したViewOutlineProviderを指定することで自由に形状を指定することができます。
インラインクラスを使って以下のような実装をしても良いでしょうし、角丸の半径を指定できる汎用クラスを作るのも良いですね。
binding.container.clipToOutline = true
binding.container.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
outline.setRoundRect(0, 0, view.width, view.height, 200 * density)
}
}
また、Drawableを指定して、そのDrawableの形状を反映させるViewOutlineProviderを作るという方法もあります。
class DrawableOutlineProvider(
private val drawable: Drawable?,
) : ViewOutlineProvider() {
private val rect: Rect = Rect()
override fun getOutline(view: View, outline: Outline) {
rect.set(0, 0, view.width, view.height)
drawable?.let {
it.bounds = rect
it.getOutline(outline)
}
}
}
この場合、drawableはViewと独立しているため、Viewのサイズを反映させてからoutlineを書き出す必要がある点に注意です。
デメリットは、他の方法に比べて実装量が多くなるところでしょうか?
その代わり自由度が高い指定をすることができます。
以上です