Help us understand the problem. What is going on with this article?

Kotlinでcustom viewを実装する時の注意点

More than 1 year has passed since last update.

KotlinでCustom Viewを実装する際コンストラクタの書き方として2つあります。

1. constructorを3つ並べる

こちらはJavaと同じ書き方で実装法です。

class KotlinView : View {

    constructor(context: Context) : super(context, null)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        ...
    }

2. @JvmOverloadsで短縮したconstructorを使う

@JvmOverloadsアノテーションを使うことでよりシンプルに実装が可能になります。

class KotlinView @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr)

1と2を比べると2の方がシンプルで使いやすく感じます。
これなら2の方法で実装すればいいじゃんとなりますが、2の書き方で上手くいかない場合があります。

EditText

EditTextを1と2それぞれの方法でCustom Viewを実装します。

KotlinEditText.kt
class KotlinEditText : EditText {

    constructor(context: Context) : super(context, null)
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        ...
    }

実行すると以下のようになります。

Screenshot_1518936561.png

次に2の方法で実装します。

class KotlinEditText @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : EditText(context, attrs, defStyleAttr)

実行すると以下のようになります。

Screenshot_1518936315.png

このことから2の方法だと上手くいってないことがわかります。

Why?

なぜこのようなことがおこったのかEditTextのソースコードをみてみます。

public class EditText extends TextView {
    public EditText(Context context) {
        this(context, null);
    }

    public EditText(Context context, AttributeSet attrs) {
        this(context, attrs, com.android.internal.R.attr.editTextStyle);
    }

    public EditText(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public EditText(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


defStyleAttrの初期値がcom.android.internal.R.attr.editTextStyleになっています。

どうやら2の方法で呼び出しを行なった場合は

public EditText(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

から呼び出しが行われるようでdefStyleAttr = 0で実行されるため、先ほどの不具合が起こったようです。

改善策① @JvmOverloadsを諦める

諦めるとこのような不具合がおりません。
しかしこれだけだと寂しいので、他の改善策を探してみます。

改善策案② defStyleAttrの初期値を変更する。

こいつが0のせいでうまくいかなかったので、思いっきり引数を変えてみます。
com.android.internal.R.attr.editTextStyleと同等の値のandroid.R.attr.editTextStyleを初期値で実行します。

class KotlinEditText @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = android.R.attr.editTextStyle
) : EditText(context, attrs, defStyleAttr)

Screenshot_1518936561.png

うまくいきました!!

改善策案③ 引数を減らす。

②の方法だと、毎回調べるのが面倒なので、今度は引数を減らしてみます。

class KotlinEditText @JvmOverloads constructor(
        context: Context, attrs: AttributeSet? = null
) : EditText(context, attrs)

こちらもうまくいきます。
ただこちらは引数を減らしてるので、他にどのような影響がでるのかわかりません。

まとめ

正直一番無難な方法である。1の方法で実装した方が、頭とか使わなく実装できると思いますが、@JvmOverloadsを使うことで、コードの見栄えが良くなります。
@JvmOverloads でのcustom viewは注意するようにしましょう。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした