Мне нужны все три конструктора для пользовательского представления 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)
? Я не уверен, где он используется, но я вижу это в суперклассе. Нужен ли он мне и где он используется?
Там другая часть этого вопроса.
Ответы
Ответ 1
Если вы добавите свой пользовательский View
из xml
также как:
<com.mypack.MyView
...
/>
вам понадобится конструктор public MyView(Context context, AttributeSet attrs)
, иначе вы получите Exception
, когда Android попытается раздуть ваш View
.
Если вы добавите View
из xml
, а также укажите атрибут android:style
, например:
<com.mypack.MyView
style="@styles/MyCustomStyle"
...
/>
также будет вызываться второй конструктор и по умолчанию стиль MyCustomStyle
перед применением явных атрибутов XML.
Третий конструктор обычно используется, когда вы хотите, чтобы все представления в вашем приложении имели один и тот же стиль.
Ответ 2
Если вы переопределите все три конструктора, не используйте CASCADE 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
в качестве стиля attr.
Ответ 3
MyView (контекст контекста)
Используется при программном преобразовании Views.
MyView (контекст контекста, AttributeSet attrs)
Используется LayoutInflater
для применения атрибутов xml. Если один из этих атрибутов имеет имя style
, атрибуты будут искать стиль перед поиском явных значений в XML файле макета.
MyView (контекст контекста, AttributeSet attrs, int defStyleAttr)
Предположим, вы хотите применить стиль по умолчанию для всех виджетов, не указывая style
в каждом файле макета. Для примера сделайте все флажки розовыми по умолчанию. Вы можете сделать это с помощью defStyleAttr, и среда будет искать стиль по умолчанию в вашей теме.
Обратите внимание, что defStyleAttr
было некорректно названо defStyle
некоторое время назад, и есть некоторое обсуждение о том, действительно ли этот конструктор нужен или нет. См. https://code.google.com/p/android/issues/detail?id=12683
MyView (контекст контекста, 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();
}
Всего
Если вы реализуете свои собственные представления, нужны только два первых конструктора и могут быть вызваны каркасом.
Если вы хотите, чтобы ваши представления были расширяемыми, вы можете реализовать 4-й конструктор для детей вашего класса, чтобы иметь возможность использовать глобальный стиль.
Я не вижу реального варианта использования для третьего конструктора. Может быть, ярлык, если вы не предоставляете стиль по умолчанию для своего виджета, но по-прежнему хотите, чтобы ваши пользователи могли это сделать. Не должно быть так много.
Ответ 4
Третий конструктор намного сложнее. Позвольте мне привести пример.
Support-v7 SwitchCompact
пакет поддерживает атрибут thumbTint
и trackTint
с 24 версии, а 23 версия не поддерживает их. Теперь вы хотите поддержать их в 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();
}
Это традиционный стиль кода. Примечание. Мы передаем 0 в третий параметр здесь. Когда вы запускаете код, вы обнаружите, что getThumbDrawable()
всегда возвращает null, как это странно, потому что метод getThumbDrawable()
- это метод суперкласса SwitchCompact
.
Если вы передадите R.attr.switchStyle
в третий парам, все будет хорошо. Итак, почему?
Третий параметр - простой атрибут. Атрибут указывает на ресурс стиля. В приведенном выше случае система найдет атрибут switchStyle
в текущей теме, к счастью, система находит его.
В frameworks/base/core/res/res/values/themes.xml
вы увидите:
<style name="Theme">
<item name="switchStyle">@style/Widget.CompoundButton.Switch</item>
</style>
Ответ 5
Если вам нужно включить три конструктора, например, тот, который сейчас обсуждается, вы тоже можете это сделать.
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();
}