Chcę naprawić moje widoki nagłówków u góry ekranu, jak na obrazku poniżej i bez korzystania z zewnętrznych bibliotek.
W moim przypadku nie chcę tego robić alfabetycznie. Mam dwa różne typy widoków (nagłówek i normalny). Chcę tylko naprawić górny, ostatni nagłówek.
android
header
android-recyclerview
sticky
Jaume Colom
źródło
źródło
Odpowiedzi:
Tutaj wyjaśnię, jak to zrobić bez zewnętrznej biblioteki. To będzie bardzo długi post, więc przygotuj się.
Przede wszystkim chciałbym podziękować @ tim.paetz, którego post zainspirował mnie do wyruszenia w podróż polegającą na implementacji moich własnych lepkich nagłówków przy użyciu
ItemDecoration
s. Pożyczyłem niektóre części jego kodu w mojej implementacji.Jak mogłeś już doświadczyć, jeśli próbowałeś to zrobić samemu, bardzo trudno jest znaleźć dobre wyjaśnienie, JAK właściwie zrobić to za pomocą tej
ItemDecoration
techniki. Mam na myśli, jakie są kroki? Jaka jest logika za tym? Jak ustawić nagłówek na górze listy? Brak znajomości odpowiedzi na te pytania sprawia, że inni korzystają z zewnętrznych bibliotek, podczas gdy robienie tego samemu przy użyciuItemDecoration
jest całkiem proste.Warunki początkowe
list
z elementów innego typu (nie w sensie „typów Java”, ale w sensie typów „nagłówek / element”).list
musi być pozycją nagłówka.Tutaj podaję pełny kod mojego
RecyclerView.ItemDecoration
callHeaderItemDecoration
. Następnie szczegółowo wyjaśniam podjęte kroki.Logika biznesowa
Jak więc sprawić, by się przykleił?
Ty nie. Nie możesz zrobić wybranego
RecyclerView
elementu, po prostu zatrzymaj się i trzymaj na górze, chyba że jesteś guru niestandardowych układów i znasz ponad 12 000 linii kodu naRecyclerView
pamięć. Tak więc, jak zawsze w przypadku projektu interfejsu użytkownika, jeśli nie możesz czegoś zrobić, udawaj. Po prostu rysujesz nagłówek na górze wszystkiego, używającCanvas
. Powinieneś także wiedzieć, które elementy użytkownik może w danej chwili zobaczyć. Tak się po prostu dzieje, żeItemDecoration
może dostarczyć zarównoCanvas
informacji, jak i widocznych przedmiotów. Oto podstawowe kroki:W
onDrawOver
metodzieRecyclerView.ItemDecoration
uzyskania pierwszego (górnego) elementu, który jest widoczny dla użytkownika.Określ, który nagłówek go reprezentuje.
Narysuj odpowiedni nagłówek na górze RecyclerView przy użyciu
drawHeader()
metody.Chcę również zaimplementować zachowanie, gdy nowy nadchodzący nagłówek spotyka się z górnym: powinien wyglądać na to, że nadchodzący nagłówek delikatnie wypycha aktualny górny nagłówek z widoku i ostatecznie zajmuje jego miejsce.
Ta sama technika „rysowania na wierzchu wszystkiego” ma tutaj zastosowanie.
Określ, kiedy górny „zablokowany” nagłówek spotyka się z nowym nadchodzącym.
Zdobądź ten punkt kontaktowy (czyli dolną część lepkiego nagłówka, który narysowałeś, i górę nadchodzącego nagłówka).
Jeśli element na liście przekracza ten „punkt kontaktowy”, przerysuj swój przyklejony nagłówek, tak aby jego dół znajdował się na górze elementu, dla którego nastąpiło naruszenie. Osiągasz to za pomocą
translate()
metodyCanvas
. W rezultacie punkt początkowy górnego nagłówka będzie poza widocznym obszarem i będzie wyglądał, jakby był „wypychany przez nadchodzący nagłówek”. Kiedy zniknie, narysuj nowy nagłówek na górze.Resztę wyjaśniają komentarze i dokładne adnotacje w podanym przeze mnie fragmencie kodu.
Użycie jest proste:
Twój
mAdapter
musi wdrożyćStickyHeaderInterface
go do pracy. Wdrożenie zależy od posiadanych danych.Na koniec udostępniam tutaj gif z półprzezroczystymi nagłówkami, abyś mógł uchwycić pomysł i faktycznie zobaczyć, co się dzieje pod maską.
Oto ilustracja koncepcji „po prostu rysuj na wierzchu wszystkiego”. Możesz zobaczyć, że istnieją dwa elementy „nagłówek 1” - jeden, który rysujemy i pozostaje na górze w zablokowanej pozycji, a drugi, który pochodzi ze zbioru danych i przenosi się ze wszystkimi pozostałymi elementami. Użytkownik nie zobaczy jego wewnętrznego działania, ponieważ nie będziesz mieć półprzezroczystych nagłówków.
A oto co dzieje się w fazie „wypychania”:
Mam nadzieję, że to pomogło.
Edytować
Oto moja rzeczywista implementacja
getHeaderPositionForItem()
metody w adapterze RecyclerView:Nieco inna implementacja w Kotlinie
źródło
private View getHeaderViewForItem(int itemPosition, RecyclerView parent) { int headerPosition = mListener.getHeaderPositionForItem(itemPosition); if(headerPosition != mCurrentHeaderIndex) { mCurrentHeader = mListener.createHeaderView(headerPosition, parent); mCurrentHeaderIndex = headerPosition; } return mCurrentHeader; }
Najłatwiejszym sposobem jest po prostu utworzenie dekoracji przedmiotu dla Twojego RecyclerView.
}
XML dla Twojego nagłówka w pliku recycling_section_header.xml:
I na koniec, aby dodać dekorację przedmiotu do swojego RecyclerView:
Dzięki tej dekoracji przedmiotu możesz albo przypiąć / przykleić nagłówek, albo nie, używając tylko wartości logicznej podczas tworzenia dekoracji przedmiotu.
Kompletny przykład roboczy można znaleźć na github: https://github.com/paetztm/recycler_view_headers
źródło
wrap_content
), Chciałbyś również uruchomićfixLayoutSize
po ustawieniu tekstu tytułu.Zrobiłem własną odmianę rozwiązania Sevastyana powyżej
... a oto implementacja StickyHeaderInterface (zrobiłem to bezpośrednio w adapterze recyklera):
Tak więc w tym przypadku nagłówek nie jest tylko rysowaniem na płótnie, ale widokiem z selektorem lub ripple, nasłuchiwaniem kliknięć itp.
źródło
recyclerView.addItemDecoration(HeaderItemDecoration(recyclerView, adapter))
. Przepraszamy, nie mogę znaleźć przykładu realizacji, z którego korzystałem. Zredagowałem odpowiedź - dodałem tekst do komentarzykażdemu, kto szuka rozwiązania problemu migotania / migania, gdy już masz
DividerItemDecoration
. wydaje się, że rozwiązałem to w następujący sposób:wydaje się, że działa, ale czy ktoś może potwierdzić, że nic innego nie zepsułem?
źródło
Możesz sprawdzić i podjąć implementację klasy
StickyHeaderHelper
w moim projekcie FlexibleAdapter i dostosować ją do swojego przypadku użycia.Ale sugeruję użycie biblioteki, ponieważ upraszcza i reorganizuje sposób, w jaki zwykle implementujesz adaptery dla RecyclerView: nie wymyślaj ponownie koła.
Powiedziałbym również, nie używaj dekoratorów ani przestarzałych bibliotek, a także nie używaj bibliotek, które robią tylko 1 lub 3 rzeczy, będziesz musiał sam scalić implementacje innych bibliotek.
źródło
Decorator
s?Kolejne rozwiązanie oparte na nasłuchiwaniu przewijania. Warunki początkowe są takie same jak w odpowiedzi Sewastiańskiej
Układ dla ViewHolder i lepkiego nagłówka.
item_header.xml
Układ dla RecyclerView
Klasa dla HeaderItem.
To wszystko jest przydatne. Implementacja adaptera ViewHolder i innych rzeczy nie jest dla nas interesująca.
Interfejs do widoku nagłówka powiązania.
źródło
for (int i = position; position >= 0; i--){ //should be i >= 0
Siema,
Tak to się robi, jeśli chcesz mieć tylko jeden rodzaj uchwytu, który zaczyna wysuwać się z ekranu (nie dbamy o żadne sekcje). Jest tylko jeden sposób bez łamania wewnętrznej logiki RecyclerView recyklingu elementów, a to polega na zawyżaniu dodatkowego widoku na górze elementu nagłówka recyklingu i przekazaniu do niego danych. Niech przemówi kod.
A potem po prostu zrób to w swoim adapterze:
Gdzie YOUR_STICKY_VIEW_HOLDER_TYPE jest viewType twojego, co ma być lepkim uchwytem.
źródło
Dla tych, którzy mogą się martwić. Opierając się na odpowiedzi Sevastyana, jeśli chcesz, aby był on przewijany w poziomie. Po prostu zmień wszystko
getBottom()
nagetRight()
igetTop()
nagetLeft()
źródło
Odpowiedź już tu jest. Jeśli nie chcesz korzystać z żadnej biblioteki, możesz wykonać następujące kroki:
Wyjaśnienie:
W
onCreateViewHolder
metodzie możemy sprawdzićviewType
iw zależności od wartości (nasz "specjalny" rodzaj) nadmuchać specjalny układ.Na przykład:
gdzie
class ItemElement
iclass TitleElement
może wyglądać jak zwykłyViewHolder
:A więc idea tego wszystkiego jest interesująca. Ale jestem zainteresowany, czy jest to skuteczne, ponieważ musimy posortować listę danych. Myślę, że to zmniejszy prędkość. Jeśli masz jakieś uwagi na ten temat, napisz do mnie :)
A także otwarte pytanie: jak utrzymać „specjalny” układ na górze, podczas gdy przedmioty są poddawane recyklingowi. Może połączyć to wszystko z
CoordinatorLayout
.źródło