しめ鯖日記

swift, iPhoneアプリ開発, ruby on rails等のTipsや入門記事書いてます

【Kotlin】XML用の独自の属性を定義する

下のmyTextのように自分独自の属性を定義して使う方法を調べてみました。

<TextView
    app:myText="Test" />

定義res/valuesにattrs.xmlに下のように記載するだけです。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyAttributes">
        <attr name="myText" format="string" />
        <attr name="myValue" format="integer" />
    </declare-styleable>
</resources>

あとはレイアウトファイルにxmlns:app="http://schemas.android.com/apk/res-auto"を追加すればapp:myTextでアクセスできるようになります。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_first_fragment"
        app:myText="test" />
</LinearLayout>

属性の型はstringやinteger以外にもbooleanやcolorなど様々なものがあります。
レイアウト以外ではこの型に合う値以外を入れるとエラーが出るようになります。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="MyAttributes">
        <attr name="myValue2" format="boolean" />
        <attr name="myValue3" format="color" />
        <attr name="myValue4" format="enum">
            <enum name="test1" value="1" />
            <enum name="test2" value="2" />
        </attr>
    </declare-styleable>
</resources>

この属性ですが下のように独自のViewを作った時に活用できます。

<com.example.myapplication.CustomView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:myText="test" />

セットした属性は下の形で取得できます。

class CustomView(context: Context, attributeSet: AttributeSet) : LinearLayout(context, attributeSet) {
    init {
        val styledAttrs = context.obtainStyledAttributes(attributeSet, R.styleable.MyAttributes)
        val textView = TextView(context).apply {
            text = styledAttrs.getString(R.styleable.MyAttributes_myText)
        }
        addView(textView)
    }
}

文字列を無理やりIntなどにしようとするとandroid.view.InflateExceptionでクラッシュします。

styledAttrs.getString(R.styleable.MyAttributes_myText) // → test
styledAttrs.getInt(R.styleable.MyAttributes_myText, -1) // → クラッシュ
styledAttrs.getBoolean(R.styleable.MyAttributes_myText, false) // → クラッシュ

ただ数字を入れていた場合は普通に取得する事が可能です。

<com.example.myapplication.CustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:myText="1" />

XMLでセットしてない場合はnullが返ってきます。
IntやBoolの場合はデフォルト値が返ってきます。

<com.example.myapplication.CustomView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />