Нужны ли мне все три конструктора для пользовательского представления Android?
при создании пользовательского представления, я заметила, что многие люди, кажется, делают это так:
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)? Я не уверен, где он используется, но я вижу его в супер классе. Нужен ли он мне, и где он используется?
есть еще одна часть этого вопроса.
6 ответов:
если вы добавите свой пользовательский
ViewСxmlи так :<com.mypack.MyView ... />вам понадобится конструктор
public MyView(Context context, AttributeSet attrs), в противном случае вы получитеExceptionкогда Android пытается надуть своегоView.если вы добавляете
ViewСxmlа также указатьandroid:styleатрибут, как :<com.mypack.MyView style="@styles/MyCustomStyle" ... />2-й конструктор также будет вызван и по умолчанию стиль
MyCustomStyleперед применением явных атрибутов XML.в третий конструктор обычно используется, когда вы хотите, чтобы все представления в вашем приложении имели одинаковый стиль.
если вы переопределяете все три конструктора, пожалуйста, не КАСКАДИРУЙТЕ
this(...)звонки. Вместо этого вы должны делать это: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как стиль attr.
MyView (контекст контекст)
используется при создании экземпляров представлений программно.
MyView (контекст контекст, AttributeSet attrs)
используемого
LayoutInflaterдля применения атрибутов xml. Если один из этих атрибутов называетсяstyle, атрибуты будут искать стиль перед поиском явных значений в xml-файле макета.MyView (контекст context, AttributeSet attrs, int defStyleAttr)
Предположим, вы хотите применить стиль по умолчанию для всех виджетов без необходимости указывать
styleв каждом файле макета. Для примера сделайте все флажки розовыми по умолчанию. Вы можете сделать это с помощью defStyleAttr, и платформа будет искать стиль по умолчанию в вашей теме.отметим, что
defStyleAttrбыло неправильно названоdefStyleнекоторое время назад и есть некоторые дискуссии о том, действительно ли этот конструктор нужен или нет. Видеть https://code.google.com/p/android/issues/detail?id=12683MyView (контекст context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
3-й конструктор работает хорошо, если у вас есть контроль над базовой темой приложений. Это работает для google, потому что они отправляют свои виджеты вдоль боковых тем по умолчанию. Но предположим, что вы пишете библиотеку виджетов и хотите, чтобы стиль по умолчанию был установлен без необходимости настройки пользователей тема. Теперь вы можете сделать это с помощью
defStyleResустановив его в значение по умолчанию в 2 первые конструкторы: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-й конструктор. Возможно, ярлык, если вы не предоставляете стиль по умолчанию для своего виджета, но все же хотите, чтобы ваши пользователи могли это сделать. Этого не должно было случиться.
Котлин, кажется, забирает много этой боли:
class MyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : View(context, attrs, defStyle)@JvmOverloads будет генерировать все необходимые конструкторы (см. эту аннотацию документация), каждый из которых предположительно вызывает super (). Затем просто замените свой метод инициализации блоком Kotlin init {}. Шаблонный код исчез!
третий конструктор намного сложнее.Позвольте мне привести пример.
поддержка-v7
SwitchCompactпакет поддерживаетthumbTintиtrackTintатрибут с 24 версии, в то время как 23 версия не поддерживает их.Теперь вы хотите, чтобы поддержать их в 23 версии и как вы будете делать, чтобы достичь этого?мы предполагаем использовать пользовательский вид
SupportedSwitchCompactвыходит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(); }это традиционный стиль кода.обратите внимание, что мы передаем 0 в третий парам здесь. Когда вы запустите код, вы найдете
getThumbDrawable()всегда возвращать null, как это странно, потому что методgetThumbDrawable()это супер классSwitchCompact' s метод.если вы передадите
R.attr.switchStyleк третьему параму, все идет well.So зачем?третий параметр-это простой атрибут. Атрибут указывает на стиль resource.In над случаем, система найдет в текущей теме, К счастью, система находит его.
на
frameworks/base/core/res/res/values/themes.xml, вы увидим:<style name="Theme"> <item name="switchStyle">@style/Widget.CompoundButton.Switch</item> </style>
Если вам нужно включить три конструктора, как тот, который обсуждается сейчас, вы можете сделать это тоже.
public MyView(Context context) { this(context,null,0); } public MyView(Context context, AttributeSet attrs) { this(context,attrs,0); } public MyView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); doAdditionalConstructorWork(); }
Comments