Нужны ли мне все три конструктора для пользовательского представления 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)? Я не уверен, где он используется, но я вижу его в супер классе. Нужен ли он мне, и где он используется?



есть еще одна часть этого вопроса.

335   6  

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=12683

MyView (контекст 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

    Ничего не найдено.