woshidan's blog

そんなことよりコードにダイブ。

ShapeDrawableのRoundRectShapeとGradientDrawableをそれぞれ使って角丸ボタン作ってみた

ShapeDrawableのRoundRectShape、あるいは、GradientDrawableを使うとコードからフチの余白や色を指定できる形で角丸四角形の背景を持つボタンが作ることができます。

もともとShapeDrawableで書いていたのですが、こちらの記事でShapeDrawableのリソースをGradientDrawableコンパイルされていることを知り、GradientDrawableで書いてみたらスッキリ記述できたので書き直した、という話です。

どちらにせよ、リソースファイルから読み込んだほうが基本的に高速なので、あまり表示頻度が多くない箇所をカスタマイズして表示したいとか、そういった場合に使えば良いと思います。

ShapeDrawableのRoundRectShapeで作る場合

同じ指定をxmlで記述した場合

今回はxmlで記述した場合は下記のようになる指定をコードで実装することにします。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
    <padding android:left="@dimen/button_padding_horizontal" />
    <padding android:top="@dimen/button_padding_vertical" />
    <padding android:right="@dimen/button_padding_horizontal" />
    <padding android:bottom="@dimen/button_padding_vertical" />
    <!-- 上記の指定はButton要素に下記属性を追加するのと同じ結果となる。
      android:paddingLeft="@dimen/button_padding_horizontal"
      android:paddingTop="@dimen/button_padding_vertical"
      android:paddingRight="@dimen/button_padding_horizontal"
      android:paddingBottom="@dimen/button_padding_vertical"  -->
    <!-- デフォルトのボタンではButton要素は
      paddingを設定しなくてもButton要素に余白を持っているが、それは
      android.R.drawable.btn_default_normal.xmlなどで
      paddingが指定されているため
       -->
    <solid android:color="#f00"/>
    <corners android:radius="@dimen/button_round_radius"/>
</shape>

RoundRectShapeを利用してコードで記述した場合

        Button button = (Button) findViewById(R.id.button_bg_code);

        // 角丸の設定
        int roundRadius = getResources().getDimensionPixelSize(R.dimen.button_round_radius);
        ShapeDrawable shape = new ShapeDrawable();
        shape.setShape(new RoundRectShape(new float[] {roundRadius, roundRadius, roundRadius, roundRadius, roundRadius, roundRadius, roundRadius, roundRadius},
                null,     // 背景のうち、真ん中の方をくりぬいた形にすることができるのですが、その領域の大きさをRectFで指定可能. 利用しない(=一色塗りつぶしにする)場合はnull
                null));   // 背景のうち、くりぬいた部分の長方形の角丸指定. 利用しない(=くりぬいた部分は長方形のまま)場合はnull

        // 余白の設定
        int horizontalPadding = getResources().getDimensionPixelSize(R.dimen.button_padding_horizontal);
        int verticalPadding = getResources().getDimensionPixelSize(R.dimen.button_padding_vertical);
        shape.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
        shape.getPaint().setColor(Color.RED);

        if (BuildConfig.VERSION_CODE >= 16) {
            button.setBackground(shape);
        } else {
            button.setBackgroundDrawable(shape);
        }
<!-- レイアウト -->
    <Button
        android:id="@+id/button_bg_resource"
        android:layout_below="@id/some_element"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/test"
        android:layout_marginTop="8dp" <!-- 見やすくするためつけてる -->
        android:text="TestTestTestTest" />

    <Button
        android:id="@+id/button_bg_code"
        android:layout_below="@id/button_bg_resource"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp" <!-- 見やすくするためつけてる -->
        android:text="TestTestTestTest" />
<!-- dimenリソースの設定 -->
<resources>
    <dimen name="button_round_radius">8dp</dimen>

    <!-- この辺の元ネタはこちら https://github.com/android/platform_frameworks_base/blob/c29fff50322599f53feadf9cf87df9956c9ac44e/core/res/res/values/dimens_material.xml#L109-L116 -->
    <dimen name="button_padding_horizontal">8dp</dimen>
    <dimen name="button_padding_vertical">4dp</dimen>
</resources>

見た目はこんな感じです。上がdrawableリソースで背景を指定したボタンで下がコードで背景を指定したボタンになります。

f:id:woshidan:20170509141454p:plain

GradientDrawableで作る場合

コードでの記述

        Button button = (Button) findViewById(R.id.button_bg_code);

        // 角丸の設定
        int roundRadius = getResources().getDimensionPixelSize(R.dimen.button_round_radius);

        GradientDrawable gradientDrawable = new GradientDrawable();
        gradientDrawable.setCornerRadius(roundRadius);
        gradientDrawable.setColor(Color.RED);

        // 余白の設定はButton要素の属性でやる

        if (BuildConfig.VERSION_CODE >= 16) {
            button.setBackground(gradientDrawable);
        } else {
            button.setBackgroundDrawable(gradientDrawable);
        }
<!-- レイアウト -->
    <Button
        android:id="@+id/button_bg_resource"
        android:layout_below="@id/some_element"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/test"
        android:layout_marginTop="8dp"  <!-- 見やすくするためつけてる -->
        android:text="TestTestTestTest" />

    <Button
        android:id="@+id/button_bg_code"
        android:layout_below="@id/button_bg_resource"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="@dimen/button_padding_horizontal"
        <!-- GradientDrawableの場合はpaddingを設定するメソッドはないので、
        View側にpaddingの指定を置く -->
        android:paddingTop="@dimen/button_padding_vertical"
        android:paddingRight="@dimen/button_padding_horizontal"
        android:paddingBottom="@dimen/button_padding_vertical"
        android:layout_marginTop="8dp" <!-- 見やすくするためつけてる -->
        android:text="TestTestTestTest" />

見た目は変わってません。

参考