При создании собственного представления я заметил, что многие люди делают это так:
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)
? Не уверен, где это используется, но вижу в суперклассе. Нужен ли он мне и где его используют?
Есть еще одна часть этого вопроса .
источник
Если вы переопределите все три конструктора, НЕ КАСКАДЫ
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
атрибут стиля.источник
MyView (контекст контекста)
Используется при программном создании экземпляров Views.
MyView (контекст контекста, атрибуты AttributeSet)
Используется
LayoutInflater
для применения атрибутов xml. Если один из этих атрибутов названstyle
, атрибуты будут проверяться по стилю перед поиском явных значений в XML-файле макета.MyView (контекст контекста, атрибуты AttributeSet, int defStyleAttr)
Предположим, вы хотите применить стиль по умолчанию ко всем виджетам без необходимости указывать его
style
в каждом файле макета. Например, по умолчанию сделайте все флажки розовыми. Вы можете сделать это с помощью defStyleAttr, и фреймворк будет искать стиль по умолчанию в вашей теме.Обратите внимание, что некоторое время назад он
defStyleAttr
был неправильно назван,defStyle
и есть некоторые дискуссии о том, действительно ли этот конструктор нужен или нет. См. Https://code.google.com/p/android/issues/detail?id=12683MyView (контекст контекста, атрибуты AttributeSet, int defStyleAttr, int defStyleRes)
Третий конструктор работает хорошо, если у вас есть контроль над базовой темой приложений. Это работает для Google, потому что они поставляют свои виджеты вместе с темами по умолчанию. Но предположим, что вы пишете библиотеку виджетов и хотите установить стиль по умолчанию, при этом вашим пользователям не нужно настраивать свою тему. Теперь вы можете сделать это
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-й конструктор для дочерних элементов вашего класса, чтобы иметь возможность использовать глобальный стиль.
Я не вижу реального варианта использования третьего конструктора. Может быть, это ярлык, если вы не предоставляете стиль по умолчанию для своего виджета, но все же хотите, чтобы ваши пользователи могли это сделать. Этого не должно случиться.
источник
Котлин, кажется, снимает большую часть этой боли:
class MyView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : View(context, attrs, defStyle)
@JvmOverloads сгенерирует все необходимые конструкторы (см. Документацию к этой аннотации ), каждый из которых предположительно вызывает super (). Затем просто замените свой метод инициализации блоком Kotlin init {}. Код шаблона пропал!
источник
Третий конструктор намного сложнее, позвольте мне привести пример.
SwitchCompact
Пакет support -v7 поддерживает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
.Если перейти
R.attr.switchStyle
к третьему параметру, все идет хорошо, так почему?Третий параметр - простой атрибут. Атрибут указывает на ресурс стиля. В приведенном выше случае система найдет
switchStyle
атрибут в текущей теме, к счастью, система найдет его.В
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(); }
источник