LayoutInflater.inflate
Dokumentacja nie jest dokładnie wyczyścić mi o celów attachToRoot
parametru.
attachToRoot : czy zawyżona hierarchia powinna być dołączona do parametru root? Jeśli false, root jest używany tylko do utworzenia poprawnej podklasy LayoutParams dla widoku root w XML.
Czy ktoś mógłby wyjaśnić bardziej szczegółowo, w szczególności, czym jest widok główny, a może pokazać przykład zmiany w zachowaniu między true
i false
wartościami?
android
android-layout
android-view
layout-inflater
Jeff Axelrod
źródło
źródło
Odpowiedzi:
TERAZ LUB NIE TERAZ
Główną różnicą między „trzecim” parametrem attachToRoot, który ma wartość true lub false, jest to.
true: dodaj widok potomka do rodzica PRAWO TERAZ
false: dodaj widok potomka do rodzica NIE TERAZ .
Dodaj to później. `
Później używasz np
parent.addView(childView)
Częstym nieporozumieniem jest to, że jeśli parametr attachToRoot ma wartość false, widok potomny nie zostanie dodany do elementu nadrzędnego. ŹLE
W obu przypadkach widok potomny zostanie dodany do ParentView. To tylko kwestia czasu .
jest równa
WIELKIE NIE NIE
Nigdy nie należy przekazywać attachToRoot jako wartości true, jeśli nie jesteś odpowiedzialny za dodanie widoku potomka do rodzica.
Np. Podczas dodawania fragmentu
jeśli podasz trzeci parametr jako true, otrzymasz IllegalStateException z powodu tego faceta.
Ponieważ już przez pomyłkę dodałeś fragment potomny w onCreateView (). Wywołanie add powie ci, że widok potomny jest już dodany do nadrzędnego Stąd IllegalStateException .
W tym przypadku nie jesteś odpowiedzialny za dodanie childView, FragmentManager jest odpowiedzialny. Więc zawsze podawaj false w tym przypadku.
UWAGA: Przeczytałem również, że ParentView nie dostanie childView touchEvents, jeśli attachToRoot ma wartość false. Ale nie przetestowałem tego.
źródło
FragmentManager
, dziękuję!Jeśli ustawione na true, to kiedy twój układ zostanie zawyżony, zostanie automatycznie dodany do hierarchii widoków grupy ViewGroup określonej w drugim parametrze jako dziecko. Na przykład, jeśli parametr root był a,
LinearLayout
wówczas nadmuchany widok zostanie automatycznie dodany jako element potomny tego widoku.Jeśli jest ustawiony na false, układ zostanie zawyżony, ale nie zostanie dołączony do żadnego innego układu (więc nie będzie rysowany, odbiera zdarzeń dotykowych itp.).
źródło
false
naattachToRoot
czasie moja Fragment użytkownikaonCreateView
. To rozwiązało problem i jeszcze układ fragment jest widoczny i aktywny, mimo swojej odpowiedzi. Co się dzieje? tutaj?true
, widok jest dołączony do drugiego parametru, który jestcontainer
, ale potem mówisz, że fragment jest automatycznie dołączanyonCreateView()
, więc o ile rozumiem, trzeci parametr jest bezużyteczny i powinien zostać ustawionyfalse
zawsze?onCreateView
. Jeśli napompujesz kolejne układy do tego widoku głównego lub napompujesz w innym kontekście (np. W działaniu), wtedy jest to przydatne.Wygląda na to, że w odpowiedziach jest dużo tekstu, ale brak kodu, dlatego postanowiłem ożywić to stare pytanie za pomocą przykładu kodu, w kilku odpowiedziach wspomnianych przez ludzi:
Co to właściwie oznacza w kodzie (co rozumie większość programistów):
Zauważ, że poprzedni kod dodaje układ
R.layout.child_view
jako element potomny zMyCustomLayout
powoduattachToRoot
parametrówtrue
i przypisuje parametry układu elementu nadrzędnego dokładnie w taki sam sposób, jakbym używaładdView
programowo lub tak, jakbym to zrobił w xml:Poniższy kod wyjaśnia scenariusz przy przekazywaniu
attachRoot
jakofalse
:W poprzednim kodzie określasz, że chcesz
myView
być jego własnym obiektem głównym i nie dołączasz go do żadnego elementu nadrzędnego, później dodaliśmy go jako część,LinearLayout
ale przez chwilę był to widok autonomiczny (bez elementu nadrzędnego).To samo dzieje się z Fragmentami, możesz dodać je do już istniejącej grupy i być jej częścią lub po prostu przekazać parametry:
Aby określić, że będzie to jego własny root.
źródło
Dokumentacja i dwie poprzednie odpowiedzi powinny wystarczyć, tylko kilka myśli ode mnie.
Ta
inflate
metoda służy do nadmuchiwania plików układu. Z tymi zawyżonymi układami musisz mieć możliwość dołączenia ich bezpośrednio do elementu nadrzędnegoViewGroup
lub po prostu nadmuchania hierarchii widoków z tego pliku układu i pracy z nią poza normalną hierarchią widoków.W pierwszym przypadku
attachToRoot
parametr będzie musiał być ustawiony natrue
(lub o wiele prostsze użycieinflate
metody, która pobiera plik układu i nadrzędny katalog głównyViewGroup
(inny niżnull
)). W tym przypadkuView
zwracana jest po prostuViewGroup
metoda przekazana w metodzie,ViewGroup
do której zostanie dodana zawyżona hierarchia widoków.W przypadku drugiej opcji zwracany
View
jest katalog głównyViewGroup
z pliku układu. Jeśli pamiętasz naszą ostatnią dyskusję zinclude-merge
pytania o parę, jest to jeden z powodówmerge
ograniczenia (gdy plik układu zmerge
rootem jest zawyżony, musisz podać element nadrzędny iattachedToRoot
ustawić natrue
). Jeśli miałeś plik układu zmerge
tagiem głównym iattachedToRoot
ustawiono go na,false
wówczasinflate
metoda nie będzie miała nic do zwrócenia, ponieważmerge
nie ma odpowiednika. Ponadto, jak napisano w dokumentacji, ważna jestinflate
wersja zattachToRoot
ustawionym na,false
ponieważ można utworzyć prawidłową hierarchię widokówLayoutParams
od rodzica. Jest to ważne w niektórych przypadkach, szczególnie w przypadku dzieciAdapterView
, podklasaViewGroup
, dla którychaddView()
zestaw metod nie jest obsługiwany. Jestem pewien, że pamiętasz, używając tej linii wgetView()
metodzie:Ta linia zapewnia, że zawyżony
R.layout.row_layout
plik ma poprawną wartośćLayoutParams
zAdapterView
podklasy ustawionej w katalogu głównymViewGroup
. Jeśli nie zrobiłbyś tego, możesz mieć problemy z plikiem układu, jeśli root byłbyRelativeLayout
. TeTableLayout/TableRow
mają również specjalne i ważneLayoutParams
i powinieneś upewnić się, że widoki w nich mają poprawneLayoutParams
.źródło
Ja również mylić o tym, co było prawdziwym celem
attachToRoot
winflate
metodzie. Po nieco przestudiowaniu interfejsu użytkownika w końcu uzyskałem odpowiedź:rodzic:
w tym przypadku jest widżet / układ otaczający obiekty widoku, które chcesz nadmuchać za pomocą findViewById ().
attachToRoot:
dołącza widoki do ich elementów nadrzędnych (obejmuje je w hierarchii elementów nadrzędnych), więc każde zdarzenie dotykowe, które otrzymają widoki, zostanie również przeniesione do widoku elementu nadrzędnego. Teraz od rodzica zależy, czy chce bawić się tymi wydarzeniami, czy je zignorować. jeśli ustawione na false, nie są dodawane jako bezpośrednie dzieci rodzica, a rodzic nie odbiera żadnych zdarzeń dotykowych z widoków.
Mam nadzieję, że to rozwiąże zamieszanie
źródło
Napisałem tę odpowiedź, ponieważ nawet po przejrzeniu kilku stron StackOverflow nie byłem w stanie jasno zrozumieć, co znaczy attachToRoot. Poniżej znajduje się metoda inflate () w klasie LayoutInflater.
Spójrz na plik activity_main.xml , układ button.xml i utworzony przez mnie plik MainActivity.java .
Activity_main.xml
button.xml
MainActivity.java
Kiedy uruchomimy kod, nie zobaczymy przycisku w układzie. Wynika to z faktu, że nasz układ przycisków nie jest dodawany do głównego układu działania, ponieważ attachToRoot ma wartość false.
LinearLayout ma metodę addView (widok widoku) , której można użyć do dodania widoków do LinearLayout. Spowoduje to dodanie układu przycisku do głównego układu działania i sprawi, że przycisk będzie widoczny po uruchomieniu kodu.
Usuńmy poprzedni wiersz i zobaczmy, co się stanie, gdy ustawimy attachToRoot na true.
Ponownie widzimy, że układ przycisku jest widoczny. Wynika to z tego, że attachToRoot bezpośrednio dołącza zawyżony układ do określonego elementu nadrzędnego. Który w tym przypadku jest root LinearLayout. Tutaj nie musimy dodawać widoków ręcznie, jak to zrobiliśmy w poprzednim przypadku z metodą addView (widok widoku).
Dlaczego ludzie otrzymują wyjątek IllegalStateException, gdy parametr attachToRoot ma wartość true dla fragmentu?
Jest tak, ponieważ dla fragmentu, który już określiłeś, gdzie chcesz umieścić układ fragmentu w pliku aktywności.
Add (int rodzic, fragment Fragment) dodaje się fragment, który ma swój układ do układu nadrzędnego. Jeśli ustawimy attachToRoot jako true, otrzymasz IllegalStateException: Określone dziecko ma już rodzica. Ponieważ układ fragmentów jest już dodany do układu nadrzędnego w metodzie add ().
Zawsze powinieneś podawać wartość false dla attachToRoot, gdy nadmuchujesz Fragmenty. Zadaniem FragmentManager jest dodawanie, usuwanie i zastępowanie Fragmentów.
Wróć do mojego przykładu. Co jeśli zrobimy jedno i drugie.
W pierwszym wierszu LayoutInflater dołącza układ przycisków do układu głównego i zwraca obiekt View zawierający ten sam układ przycisków. W drugim wierszu dodajemy ten sam obiekt View do nadrzędnego układu głównego. Powoduje to ten sam wyjątek IllegalStateException, który widzieliśmy w przypadku fragmentów (określone dziecko ma już element nadrzędny).
Należy pamiętać, że istnieje inna metoda przeciążenia inflate (), która domyślnie ustawia attachToRoot na true.
źródło
Istnieje wiele nieporozumień na ten temat z powodu dokumentacji dla metody inflate ().
Ogólnie, jeśli attachToRoot ma wartość true, plik układu określony w pierwszym parametrze jest nadmuchiwany i dołączany do grupy ViewGroup określonej w drugim parametrze w tym momencie. Gdy właściwość attachToRoot ma wartość false, plik układu z pierwszego parametru jest zawyżany i zwracany jako widok, a dowolny załącznik widoku ma miejsce w innym czasie.
To chyba nie znaczy wiele, chyba że zobaczysz wiele przykładów. Podczas wywoływania LayoutInflater.inflate () w metodzie onCreateView fragmentu, będziesz chciał przekazać wartość false dla attachToRoot, ponieważ działanie powiązane z tym fragmentem jest w rzeczywistości odpowiedzialne za dodanie widoku tego fragmentu. Jeśli ręcznie pompujesz i dodajesz widok do innego widoku w późniejszym czasie, na przykład przy użyciu metody addView (), będziesz chciał przekazać wartość false dla attachToRoot, ponieważ załącznik przychodzi w późniejszym czasie.
O kilku innych unikalnych przykładach dotyczących okien dialogowych i niestandardowych widoków możesz przeczytać w poście na blogu, który napisałem na ten temat.
https://www.bignerdranch.com/blog/understanding-androids-layoutinflater-inflate/
źródło
attachToRoot
wartość true oznacza, żeinflatedView
zostanie dodany do hierarchii widoku rodzica. W ten sposób użytkownicy mogą „widzieć” i wyczuwać zdarzenia dotykowe (lub dowolne inne operacje interfejsu użytkownika). W przeciwnym razie został on właśnie utworzony, nie został dodany do żadnej hierarchii widoku, a zatem nie można go zobaczyć ani obsługiwać zdarzeń dotykowych.W przypadku programistów iOS nowszych w systemie Android
attachToRoot
wartość true oznacza, że wywołujesz tę metodę:Jeśli pójdziesz dalej, możesz zapytać: Dlaczego powinienem przekazać widok rodzica, jeśli mam taką
attachToRoot
opcjęfalse
? Jest tak, ponieważ element główny w drzewie XML potrzebuje widoku rodzica, aby obliczyć niektóre LayoutParams (np. Dopasowanie rodzica).źródło
Po zdefiniowaniu elementu nadrzędnego attachToRoot określa, czy inflator ma faktycznie dołączyć go do elementu nadrzędnego, czy nie. W niektórych przypadkach powoduje to problemy, na przykład w ListAdapter spowoduje wyjątek, ponieważ lista próbuje dodać widok do listy, ale mówi, że jest już dołączona. W innym przypadku, gdy sam nadmuchujesz widok, aby dodać do działania, może być przydatny i oszczędzić Ci linię kodu.
źródło
Na przykład mamy an
ImageView
, aLinearLayout
i aRelativeLayout
. LinearLayout jest dzieckiem RelativeLayout. będzie Hierarchia widoków.i mamy osobny plik układu dla ImageView
image_view_layout.xml
Dołącz do katalogu głównego:
setImageResource(R.drawable.np);
ImageView, musisz je znaleźć przez odniesienie do rodzica, tj.view.findById()
Nie dołączaj do katalogu głównego:
view.setImageResource(R.drawable.np);
bez odwoływania się do tegofindViewById
. Ale kontener jest określony, aby ImageView pobierał LayoutParams kontenera, dzięki czemu można powiedzieć, że odwołanie do kontenera jest tylko dla LayoutParams.źródło
attachToRoot Ustaw na true:
Wyobraź sobie, że podaliśmy przycisk w pliku układu XML z szerokością i wysokością układu ustawioną na match_parent.
Chcemy teraz programowo dodać ten przycisk do liniowego układu wewnątrz fragmentu lub działania. Jeśli nasz LinearLayout jest już zmienną składową mLinearLayout, możemy po prostu dodać przycisk w następujący sposób:
Określiliśmy, że chcemy nadmuchać Button z jego pliku zasobów układu; następnie mówimy LayoutInflater, że chcemy dołączyć go do mLinearLayout. Nasze parametry układu są honorowane, ponieważ wiemy, że przycisk zostanie dodany do LinearLayout. Typem parametrów układu przycisku powinien być LinearLayout.LayoutParams.
attachToRoot Ustaw na wartość false (nie jest wymagane, aby użyć wartości false)
Przyjrzyjmy się, kiedy chcesz ustawić attachToRoot na false. W tym scenariuszu widok określony w pierwszym parametrze inflate () nie jest w tym momencie dołączany do grupy ViewGroup w drugim parametrze.
Przypomnijmy nasz przykład z wcześniejszego przycisku, w którym chcemy dołączyć niestandardowy przycisk z pliku układu do mLinearLayout. Nadal możemy dołączyć nasz przycisk do mLinearLayout, przekazując wartość false dla attachToRoot - po prostu dodajemy go samodzielnie.
Te dwa wiersze kodu są równoważne temu, co napisaliśmy wcześniej w jednym wierszu kodu, gdy przekazaliśmy true dla attachToRoot. Przekazując fałsz, mówimy, że nie chcemy jeszcze dołączać naszego widoku do głównej grupy ViewGroup. Mówimy, że stanie się to w innym momencie. W tym przykładzie innym momentem jest po prostu metoda addView () zastosowana bezpośrednio poniżej inflacji.
Fałszywy przykład attachToRoot wymaga nieco więcej pracy, gdy ręcznie dodamy widok do grupy ViewGroup.
attachToRoot Ustaw na wartość false (wymagana jest wartość false)
Podczas nadmuchiwania i zwracania widoku fragmentu w funkcji onCreateView (), należy podać wartość false dla parametru attachToRoot. Jeśli podasz true, otrzymasz IllegalStateException, ponieważ określone dziecko ma już rodzica. Powinieneś określić, gdzie widok Twojego Fragmentu zostanie umieszczony z powrotem w Twojej Aktywności. Zadaniem FragmentManager jest dodawanie, usuwanie i zastępowanie Fragmentów.
Kontener root_viewGroup, który przechowa Twój Fragment w Twojej Aktywności, jest parametrem ViewGroup podanym w funkcji onCreateView () w Twoim Fragmentie. Jest to także grupa ViewGroup, którą przekazujesz do LayoutInflater.inflate (). FragmentManager poradzi sobie jednak z dołączaniem Widoku Fragmentu do tej grupy ViewGroup. Nie chcesz dołączać go dwa razy. Ustaw attachToRoot na false.
Dlaczego otrzymujemy nadrzędną grupę ViewGroup naszego Fragmentu, jeśli nie chcemy dołączać jej do funkcji onCreateView ()? Dlaczego metoda inflate () żąda głównej grupy ViewGroup?
Okazuje się, że nawet jeśli nie dodajemy od razu naszego świeżo napompowanego Widoku do jego nadrzędnej grupy ViewGroup, powinniśmy nadal używać LayoutParams rodzica, aby nowy widok mógł określić jego rozmiar i pozycję, gdy tylko zostanie ostatecznie dołączony.
Link: https://youtu.be/1Y0LlmTCOkM?t=409
źródło
Po prostu dzieląc się niektórymi punktami, które napotkałem podczas pracy na ten temat,
Oprócz zaakceptowanej odpowiedzi chciałbym przedstawić kilka punktów, które mogą być pomocne.
Tak więc, kiedy użyłem attachToRoot jako true, zwracany widok był typu ViewGroup, tj. Główny root nadrzędnej grupy ViewGroup, która została przekazana jako parametr dla metody inflate (layoutResource, ViewGroup, attachToRoot) , nie typu układu, który został przekazany, ale w przypadku attachToRoot jako fałsz otrzymujemy typ zwracanej funkcji tego głównego układu ViewGroup źródła .
Pozwól mi wyjaśnić na przykładzie:
Jeśli mamy układ liniowy jako układ główny, a następnie chcemy dodać do niego TextView poprzez nadmuchanie funkcję .
następnie przy użyciu attachToRoot jako funkcji true inflate zwraca widok typu LinearLayout
podczas korzystania z attachToRoot jako funkcji fałszywego nadmuchu zwraca widok typu TextView
Mam nadzieję, że to odkrycie okaże się pomocne ...
źródło