カスタムビューを作成するとき、多くの人が次のようにしていることに気付きました。
_public MyView(Context context) {
super(context);
// this constructor used when programmatically creating view
doAdditionalConstructorWork();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
// this constructor used when creating view through XML
doAdditionalConstructorWork();
}
private void doAdditionalConstructorWork() {
// init variables etc.
}
_
最初の質問は、コンストラクタMyView(Context context, AttributeSet attrs, int defStyle)
についてはどうですか?どこで使用されているのかわかりませんが、スーパークラスで見ます。必要ですか、どこで使用されますか?
この質問の別の部分 があります。
View
からカスタムxml
を追加する場合も同様です:
_ <com.mypack.MyView
...
/>
_
コンストラクターpublic MyView(Context context, AttributeSet attrs)
が必要です。そうでない場合、AndroidがException
を膨張させようとするとView
を取得します。
View
からxml
を追加し、次のように_Android:style
_属性も指定した場合:
_ <com.mypack.MyView
style="@styles/MyCustomStyle"
...
/>
_
明示的なXML属性を適用する前に、2番目のコンストラクターも呼び出され、デフォルトでMyCustomStyle
にスタイルが設定されます。
通常、3番目のコンストラクターは、アプリケーションのすべてのビューを同じスタイルにする場合に使用されます。
3つのコンストラクターをすべてオーバーライドする場合は、this(...)
CALLSをカスケードしないでください。代わりにこれを行う必要があります:
_public MyView(Context context) {
super(context);
init(context, null, 0);
}
public MyView(Context context, AttributeSet attrs) {
super(context,attrs);
init(context, attrs, 0);
}
public MyView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context, attrs, defStyle);
}
private void init(Context context, AttributeSet attrs, int defStyle) {
// do additional work
}
_
その理由は、親クラスのコンストラクタにデフォルトの属性が含まれている可能性があり、誤ってオーバーライドする可能性があるためです。たとえば、これはTextView
のコンストラクタです。
_public TextView(Context context) {
this(context, null);
}
public TextView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, com.Android.internal.R.attr.textViewStyle);
}
public TextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
_
super(context)
を呼び出さなかった場合、スタイル属性として_R.attr.textViewStyle
_を適切に設定していません。
プログラムでビューをインスタンス化するときに使用されます。
Xml属性を適用するためにLayoutInflater
によって使用されます。この属性の1つがstyle
という名前の場合、属性はレイアウトxmlファイルで明示的な値を探す前にスタイルで検索されます。
各レイアウトファイルでstyle
を指定せずに、すべてのウィジェットにデフォルトスタイルを適用するとします。たとえば、デフォルトですべてのチェックボックスをピンクにします。 defStyleAttrでこれを行うことができ、フレームワークはテーマのデフォルトスタイルを検索します。
defStyleAttr
の名前はdefStyle
と間違って付けられていたことに注意してください。このコンストラクタが本当に必要かどうかについての議論があります。 https://code.google.com/p/Android/issues/detail?id=1268 を参照してください
3番目のコンストラクターは、アプリケーションの基本テーマを制御できればうまく機能します。デフォルトのテーマと一緒にウィジェットを出荷しているので、Googleで機能しています。しかし、ウィジェットライブラリを作成していて、ユーザーがテーマを微調整する必要なくデフォルトのスタイルを設定したいとします。 2つの最初のコンストラクターでデフォルト値に設定することで、defStyleRes
を使用してこれを行うことができます。
public MyView(Context context) {
super(context, null, 0, R.style.MyViewStyle);
init();
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs, 0, R.style.MyViewStyle);
init();
}
独自のビューを実装する場合は、最初の2つのコンストラクターのみが必要であり、フレームワークから呼び出すことができます。
ビューを拡張可能にしたい場合は、クラスの子がグローバルスタイリングを使用できるように、4番目のコンストラクターを実装できます。
3番目のコンストラクターの実際の使用例は見当たりません。ウィジェットにデフォルトのスタイルを提供しないが、ユーザーにそれを許可したい場合のショートカットかもしれません。そんなに起こるべきではありません。
Kotlinはこの痛みの多くを取り除くようです:
class MyView
@JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0)
: View(context, attrs, defStyle)
@JvmOverloadsは必要なすべてのコンストラクターを生成し(そのアノテーションの documentation を参照)、それぞれがおそらくsuper()を呼び出します。次に、初期化メソッドをKotlin init {}ブロックに置き換えます。定型コードがなくなった!
3番目のコンストラクターははるかに複雑です。例を挙げてみましょう。
Support-v7 SwitchCompact
パッケージは、24バージョン以降はthumbTint
およびtrackTint
属性をサポートしますが、23バージョンはそれらをサポートしていません。これを達成するために?
カスタムビューSupportedSwitchCompact
extends SwitchCompact
を使用することを想定しています。
_public SupportedSwitchCompat(Context context) {
this(context, null);
}
public SupportedSwitchCompat(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SupportedSwitchCompat(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
mThumbDrawable = getThumbDrawable();
mTrackDrawable = getTrackDrawable();
applyTint();
}
_
従来のコードスタイルです。ここで3番目のパラメータに0を渡すことに注意してください。コードを実行すると、メソッドgetThumbDrawable()
がそのスーパークラスSwitchCompact
のメソッドであるため、getThumbDrawable()
は常にnullを返します。
_R.attr.switchStyle
_を3番目のパラメーターに渡すと、すべてがうまくいきます。
番目のパラメータは単純な属性です。この属性はスタイルリソースを指します。上記の場合、システムは幸いにも現在のテーマでswitchStyle
属性を見つけるでしょう。
_frameworks/base/core/res/res/values/themes.xml
_には、次が表示されます。
_<style name="Theme">
<item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
</style>
_