Podczas tworzenia widoku niestandardowego zauważyłem, że wiele osób robi to w ten sposób:
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.
}
Moje pierwsze pytanie brzmi: co z konstruktorem MyView(Context context, AttributeSet attrs, int defStyle)
? Nie jestem pewien, gdzie jest używany, ale widzę to w super klasie. Czy go potrzebuję i gdzie jest używany?
Jest jeszcze jedna część tego pytania .
źródło
Jeśli zastąpisz wszystkie trzy konstruktory, NIE NALEŻY POŁĄCZEŃ
this(...)
KASKADOWYCH. Zamiast tego powinieneś to zrobić:Przyczyną jest to, że klasa nadrzędna może zawierać atrybuty domyślne we własnych konstruktorach, które można przypadkowo przesłonić. Na przykład to jest konstruktor dla
TextView
:Gdybyś nie wywołał
super(context)
, nie ustawiłbyś poprawnieR.attr.textViewStyle
jako atrybutu stylu.źródło
MyView (kontekst kontekstowy)
Używane podczas programowego tworzenia widoków.
MyView (kontekst kontekstowy, atrybuty zestawu atrybutów)
Używane przez the
LayoutInflater
do stosowania atrybutów xml. Jeśli jeden z tych atrybutów jest nazwanystyle
, atrybuty będą przeszukiwane w stylu przed wyszukaniem jawnych wartości w pliku XML układu.MyView (kontekst kontekstowy, atrybuty AttributeSet, int defStyleAttr)
Załóżmy, że chcesz zastosować domyślny styl do wszystkich widżetów bez konieczności określania ich
style
w każdym pliku układu. Na przykład ustaw domyślnie wszystkie pola wyboru na różowo. Możesz to zrobić za pomocą defStyleAttr, a framework wyszuka domyślny styl w twoim motywie.Zauważ, że jakiś czas temu
defStyleAttr
został nieprawidłowo nazwanydefStyle
i jest dyskusja na temat tego, czy ten konstruktor jest naprawdę potrzebny, czy nie. Zobacz https://code.google.com/p/android/issues/detail?id=12683MyView (kontekst kontekstowy, atrybuty AttributeSet, int defStyleAttr, int defStyleRes)
Trzeci konstruktor działa dobrze, jeśli masz kontrolę nad motywem podstawowym aplikacji. To działa dla Google, ponieważ wysyłają swoje widżety obok domyślnych motywów. Ale załóżmy, że piszesz bibliotekę widżetów i chcesz, aby domyślny styl został ustawiony bez konieczności modyfikowania motywu przez użytkowników. Możesz to teraz zrobić
defStyleRes
, ustawiając wartość domyślną w dwóch pierwszych konstruktorach:W sumie
Jeśli implementujesz własne widoki, tylko dwa pierwsze konstruktory powinny być potrzebne i mogą być wywoływane przez framework.
Jeśli chcesz, aby Twoje widoki były rozszerzalne, możesz zaimplementować czwarty konstruktor dla elementów podrzędnych Twojej klasy, aby móc używać stylów globalnych.
Nie widzę prawdziwego przypadku użycia trzeciego konstruktora. Może to skrót, jeśli nie podasz domyślnego stylu widgetu, ale nadal chcesz, aby użytkownicy mogli to robić. Nie powinno się tak często dziać.
źródło
Kotlin wydaje się usuwać wiele z tego bólu:
@JvmOverloads wygeneruje wszystkie wymagane konstruktory (zobacz dokumentację tej adnotacji ), z których każdy prawdopodobnie wywoła super (). Następnie po prostu zamień swoją metodę inicjalizacji na blok Kotlin init {}. Zniknął kod schematu!
źródło
Trzeci konstruktor jest dużo bardziej skomplikowany, posłużę się przykładem.
SwitchCompact
Pakiet Support-v7 obsługujethumbTint
itrackTint
atrybut od wersji 24, podczas gdy wersja 23 ich nie obsługuje. Teraz chcesz je obsługiwać w wersji 23 i jak zamierzasz to osiągnąć?Zakładamy, że będziemy używać niestandardowych
SupportedSwitchCompact
rozszerzeń widokuSwitchCompact
.To tradycyjny styl kodu. Zauważ, że przekazujemy 0 do trzeciego parametru tutaj . Kiedy uruchomisz kod, zauważysz, że
getThumbDrawable()
zawsze zwraca wartość null, jakie to dziwne, ponieważ ta metodagetThumbDrawable()
jest metodą swojej superklasySwitchCompact
.Jeśli przejdziesz
R.attr.switchStyle
do trzeciego parametru, wszystko pójdzie dobrze, więc dlaczego?Trzeci parametr to prosty atrybut. Atrybut wskazuje na zasób stylu, w powyższym przypadku system znajdzie
switchStyle
atrybut w aktualnym motywie na szczęście system go znajdzie.W
frameworks/base/core/res/res/values/themes.xml
zobaczysz:źródło
Jeśli musisz uwzględnić trzy konstruktory, takie jak ten omawiany teraz, możesz to również zrobić.
źródło