【Android】カスタム属性を作成する【Java/Kotlin】

こんにちは!

前回はカスタムビューを作成しました。

今回はそのカスタムビューにカスタム属性を作成して追加してみましょう!

カスタム属性とは?

TextViewを例にすると

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="テキスト" />

Androidフレームワークがandroid:text=等のattributeを用意してくれているのですが、

自作したViewにはオリジナルのattributeを定義する事ができます。

オリジナルのattributeの事をカスタム属性といいます。

前提準備

今回はボタンの背景色を変更できるカスタム属性を作成しましょう

まずはカスタム属性を定義していきましょう

res/values/attrs.xmlに下記をコードを追加しましょう(XMLファイルがなければ追加が必要です)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="CustomView">
        <attr name="buttonColor" format="color" />
    </declare-styleable>
</resources>

上記を実施することによりCustomViewにbuttonColorというカラーコードが入力できるカスタム属性が作成できました。

他にも色々なデータを受け取れるformatがあるので後述します。

カスタム属性を作成するだけでは何も起こらないので設定されたCustomViewクラスでカスタム属性を取得してボタンに背景色を設定しましょう

    public CustomView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // XMLとクラスを紐づける
        View.inflate(getContext(), R.layout.view_custom, this);
        // 各ボタンのインスタンスを取得
        mTopButton = findViewById(R.id.topButton);
        mCenterButton = findViewById(R.id.centerButton);
        mBottomButton = findViewById(R.id.bottomButton);

        // TypedArrayのインスタンスを取得
        TypedArray typedArray = context.getTheme().
                obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0);
        // カラーコードを取得
        int colorInt = Color.WHITE;
        try {
            colorInt = typedArray.getColor(R.styleable.CustomView_buttonColor, Color.WHITE);
        } finally {
            typedArray.recycle();
        }
        // 各ボタンの背景色を変更
        mTopButton.setBackgroundColor(colorInt);
        mCenterButton.setBackgroundColor(colorInt);
        mBottomButton.setBackgroundColor(colorInt);
    }
    init {
        // XMLとクラスを紐づける
        View.inflate(getContext(), R.layout.view_custom, this)
        // 各ボタンのインスタンスを取得
        topButton = findViewById(R.id.topButton)
        centerButton = findViewById(R.id.centerButton)
        bottomButton = findViewById(R.id.bottomButton)

        // TypedArrayのインスタンスを取得
        val typedArray = context.theme
            .obtainStyledAttributes(attrs, R.styleable.CustomView, defStyleAttr, 0)
        // カラーコードを取得
        var colorInt: Int = Color.WHITE
        colorInt = try {
            typedArray.getColor(R.styleable.CustomView_buttonColor, Color.WHITE)
        } finally {
            typedArray.recycle()
        }
        // 各ボタンの背景色を変更
        // 各ボタンの背景色を変更
        topButton.setBackgroundColor(colorInt)
        centerButton.setBackgroundColor(colorInt)
        bottomButton.setBackgroundColor(colorInt)
    }

こちらで準備完了です。注意点等は後述します。

カスタム属性を使用する

それではカスタム属性を使用してきちんと動作しているか確認しましょう

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.example.androidstudyjava.CustomView
        android:id="@+id/customView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:buttonColor="#FF0000"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

きちんと動作していますね!

ポイント

1. attrs.xmlにカスタム属性を追加する

attrs.xmlにカスタム属性を追加しないと下記現象が発生します。

  • レイアウトXMLでビルドエラーになる
  • クラスファイルからカスタム属性のデータが取得するためのidが生成されない

要注意です。

2. TypedArrayからgetXXXを実行する際はtry分で囲む

クラスファイルでカスタム属性のデータを取得する場合はtry分で囲まないとgetXXXメソッド内でExceptionがthrowされる事があるのでクラッシュしてしまいます。

3. recycle()を実行する

TypedArrayに対してrecycle()を実行してください。(TypedArrayの再利用ができないため)

カスタム属性に入力できるデータは何?

下記が使用できます。

format説明
string文字列app:xxx=”テキスト”
float実数値app:xxx=”1.5″
integer整数値app:xxx=”15″
boolean論理値app:xxx=”false”
enum列挙値app:xxx=”hoge” <-hogeを予め定義しておく必要がある
dimension単位(spやdp)app:xxx=”15dp”
colorカラーコード app:xxx=”#FF0000″, app:xxx=”@color/hoge”
referenceリソースIDapp:xxx=”@id/hoge”
fractionパーセント(割合)app:xxx=”15%”
flagフラグ値app:xxx=”hoge” <-hogeを予め定義しておく必要がある

最後に

いかがでしたでしょうか

カスタム属性を追加することによりレイアウトXMLとクラスファイルでのみで処理が完結します。

FragmentやActivityが膨らまなくて済むのでいいですね!

それでは!

コメント

タイトルとURLをコピーしました