Zainstalowałem prosty ViewPager, który ma ImageView o wysokości 200dp na każdej stronie.
Oto mój pager:
pager = new ViewPager(this);
pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
pager.setBackgroundColor(Color.WHITE);
pager.setOnPageChangeListener(listener);
layout.addView(pager);
Pomimo wysokości ustawionej jako wrap_content, pager zawsze wypełnia ekran, nawet jeśli podgląd obrazu wynosi tylko 200dp. Próbowałem zamienić wysokość pagera na „200”, ale daje to różne wyniki przy wielu rozdzielczościach. Nie mogę dodać „dp” do tej wartości. Jak dodać 200dp do układu pagera?
Odpowiedzi:
Przesłonięcie opcji Twój pomiar w
ViewPager
następujący sposób sprawi, że uzyska wysokość największego dziecka, jakie aktualnie ma.źródło
Kolejnym bardziej ogólnym rozwiązaniem jest
wrap_content
po prostu praca.Rozszerzyłem,
ViewPager
by zastąpićonMeasure()
. Wysokość jest owinięta wokół pierwszego widoku dziecka. Może to prowadzić do nieoczekiwanych rezultatów, jeśli widoki potomne nie będą dokładnie tej samej wysokości. W tym celu można łatwo rozszerzyć klasę, aby na przykład ożywić rozmiar bieżącego widoku / strony. Ale nie potrzebowałem tego.Możesz używać tego ViewPager w swoich układach XML, tak jak oryginalny ViewPager:
Zaleta: To podejście pozwala na użycie ViewPager w dowolnym układzie, w tym RelativeLayout, do nakładania innych elementów interfejsu użytkownika.
Pozostaje jedna wada: jeśli chcesz użyć marginesów, musisz utworzyć dwa zagnieżdżone układy i nadać wewnętrznemu pożądane marginesy.
Oto kod:
źródło
Swoją odpowiedź oparłem na Danielu Lópezie Lacalle i tym poście http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ . Problem z odpowiedzią Daniela polega na tym, że w niektórych przypadkach moje dzieci miały wysokość zero. Rozwiązaniem było niestety zmierzenie dwa razy.
Pozwala to również ustawić wysokość w ViewPager, jeśli chcesz lub po prostu wrap_content.
źródło
scaleType
i podobnie,layout_width=match_parent
a takżelayout_height=wrap_content
? brakuje tam 20dp.// super has to be called in the beginning so the child views can be initialized.
<----- To był powód, musiał wywołać go na początku i na końcu funkcji onMeasure. Yippiii, wirtualne piątki na mnie dzisiaj!Właśnie odpowiadałem na bardzo podobne pytanie na ten temat i znalazłem to, gdy szukałem linku, aby poprzeć moje roszczenia, więc mam szczęście :)
Moja inna odpowiedź:
ViewPager nie obsługuje,
wrap_content
ponieważ (zwykle) nigdy nie ma załadowanych wszystkich swoich dzieci w tym samym czasie, a zatem nie może uzyskać odpowiedniego rozmiaru (opcją byłoby mieć pager, który zmienia rozmiar przy każdym przełączeniu strona).Możesz jednak ustawić dokładny wymiar (np. 150dp) i również
match_parent
działa.Możesz także dynamicznie modyfikować wymiary ze swojego kodu, zmieniając w nim
height
atrybut -attributeLayoutParams
.W zależności od potrzeb możesz utworzyć ViewPager we własnym pliku xml, z ustawieniem layout_height na 200dp, a następnie w swoim kodzie, zamiast tworzyć nowy ViewPager od zera, możesz napompować ten plik xml:
źródło
layout_height
ustawieniem nawrap_content
, ale jest jeszcze gorsza, ponieważ proste obejście ustawiania na stałą kwotę nie działa.Korzystając z odpowiedzi Daniela Lópeza Localle , stworzyłem tę klasę w Kotlin. Mam nadzieję, że zaoszczędzisz więcej czasu
źródło
Problem ten napotkałem już w kilku projektach i nigdy nie miałem kompletnego rozwiązania. Więc stworzyłem projekt github WrapContentViewPager jako zamiennik w miejscu dla ViewPager.
https://github.com/rnevet/WCViewPager
Rozwiązanie zostało zainspirowane niektórymi odpowiedziami tutaj, ale poprawia:
Zaktualizowano dla biblioteki pomocy technicznej w wersji 24, która przerwała poprzednie wdrożenie.
źródło
Właśnie wpadłem na ten sam problem. Miałem ViewPager i chciałem wyświetlić reklamę za jego przyciskiem. Rozwiązaniem, które znalazłem, było przeniesienie pagera do RelativeView i ustawienie jego layout_above na identyfikator widoku, który chcę zobaczyć poniżej. to działało dla mnie.
oto mój układ XML:
źródło
Natknąłem się również na ten problem, ale w moim przypadku miałem taki,
FragmentPagerAdapter
który dostarczałViewPager
swoje strony. Problem, który miałem, polegał na tym,onMeasure()
żeViewPager
został wywołany przed utworzeniem któregokolwiek zFragments
nich (i dlatego nie mógł się odpowiednio dopasować).Po kilku próbach i błędach odkryłem, że
finishUpdate()
metoda FragmentPagerAdapter jest wywoływana poFragments
zainicjowaniu (odinstantiateItem()
wFragmentPagerAdapter
), a także po / podczas przewijania strony. Zrobiłem mały interfejs:które przechodzę do mojego
FragmentPagerAdapter
i wołam:co z kolei pozwala mi wezwać
setVariableHeight()
mojąCustomViewPager
implementację:Nie jestem pewien, czy to najlepsze podejście, chętnie komentuję, jeśli uważasz, że jest dobre / złe / złe, ale wydaje się, że działa całkiem dobrze w mojej realizacji :)
Mam nadzieję, że to pomoże komuś tam!
EDYCJA: Zapomniałem dodać
requestLayout()
po wywołaniusuper.measure()
(inaczej nie przerysuje widoku).Zapomniałem również dodać podkładki rodzica do ostatecznej wysokości.
Porzuciłem również zachowanie oryginalnej szerokości / wysokości MeasureSpecs na korzyść stworzenia nowej w razie potrzeby. Zaktualizowałem odpowiednio kod.
Innym problemem, jaki miałem, było to, że nie zmieściłoby się ono prawidłowo w a
ScrollView
i stwierdził, że sprawca mierzył dzieckoMeasureSpec.EXACTLY
zamiastMeasureSpec.UNSPECIFIED
. Zaktualizowano, aby to odzwierciedlić.Wszystkie zmiany zostały dodane do kodu. Możesz sprawdzić historię, aby zobaczyć stare (niepoprawne) wersje, jeśli chcesz.
źródło
Innym rozwiązaniem jest aktualizacja
ViewPager
wysokości zgodnie z bieżącą wysokością stronyPagerAdapter
. Zakładając, że tworzysz swojeViewPager
strony w ten sposób:Gdzie
mPages
jest wewnętrzna listaPageInfo
struktur dodawanych dynamicznie doPagerAdapter
iCustomImageView
jest po prostu regularnaImageView
zonMeasure()
metodą przesłonięcia , która ustawia wysokość zgodnie z określoną szerokością i zachowuje proporcje obrazu.Możesz wymusić
ViewPager
wysokość wsetPrimaryItem()
metodzie:Uwaga
Math.max(height, 1)
. To naprawia irytujący błąd,ViewPager
który nie aktualizuje wyświetlanej strony (pokazuje, że jest pusta), gdy poprzednia strona ma zerową wysokość (tzn. Można ją narysować w wartości zeroCustomImageView
), każde nieparzyste przesunięcie w obie strony między dwiema stronami.źródło
item.mImageView.measure(..)
aby uzyskać właściwe wymiarygetMeasuredXXX()
metod.Podczas korzystania z treści statycznych w przeglądarce i nie chcesz żadnych fantazyjnych animacji, możesz użyć następującego pagera
źródło
źródło
Od czasu popcornowego kodu źródłowego aplikacji na Androida znalazłem to rozwiązanie, które dynamicznie dostosowuje rozmiar przeglądarki z ładną animacją w zależności od wielkości bieżącego dziecka.
https://git.popcorntime.io/popcorntime/android/blob/5934f8d0c8fed39af213af4512272d12d2efb6a6/mobile/src/main/java/pct/droid/widget/WrappingViewPager.java
źródło
Jeśli potrzebujesz programu ViewPager, który dostosuje jego rozmiar do każdego dziecka , nie tylko do największego, napisałem fragment kodu, który to robi. Pamiętaj, że po tej zmianie nie ma animacji (w moim przypadku nie jest to konieczne)
Android: flaga minHeight jest również obsługiwana.
źródło
Poprawiona odpowiedź Daniela Lópeza Lacalle'a , przepisana w Kotlinie :
źródło
Natknąłem się na ten sam problem, a także musiałem zmusić ViewPager do zawijania jego zawartości, gdy użytkownik przewijał strony. Korzystając z powyższej odpowiedzi cybergena, zdefiniowałem metodę onMeasure w następujący sposób:
W ten sposób metoda onMeasure ustala wysokość bieżącej strony wyświetlanej przez ViewPager.
źródło
Nic z sugerowanych powyżej nie działało dla mnie. Mój przypadek użycia to 4 niestandardowe przeglądarki ViewPagers
ScrollView
. Najlepsze z nich są mierzone na podstawie współczynnika kształtu, a reszta malayout_height=wrap_content
. Próbowałem rozwiązań cybergen , Daniel López Lacalle . Żadne z nich nie działa dla mnie w pełni.Domyślam się, że cybergen nie działa na stronie> 1, ponieważ oblicza wysokość pagera na podstawie strony 1, która jest ukryta, jeśli przewiniesz dalej.
Zarówno cybergen, jak i Daniel López Lacalle mają w moim przypadku dziwne zachowanie: 2 z 3 są załadowane ok, a 1 losowo ma wysokość 0. Wygląda na to, że wywołano je
onMeasure
zanim dzieci zostały zaludnione. Więc wymyśliłem kombinację tych 2 odpowiedzi + moje własne poprawki:Pomysł polega na
ViewPager
obliczeniu wymiarów dzieci i zapisaniu obliczonej wysokości pierwszej strony w parametrach układuViewPager
. Nie zapomnij ustawić wysokości układu fragmentu, aby wwrap_content
przeciwnym razie można uzyskać wysokość = 0. Użyłem tego:Pamiętaj, że to rozwiązanie działa świetnie, jeśli wszystkie strony mają tę samą wysokość . W przeciwnym razie musisz ponownie obliczyć
ViewPager
wysokość na podstawie bieżącego aktywnego dziecka. Nie potrzebuję tego, ale jeśli zaproponujesz rozwiązanie, chętnie zaktualizuję odpowiedź.źródło
Dla osób mających ten problem i kodujących dla Xamarin Android w C #, może to być również szybkie rozwiązanie:
Jest to szczególnie przydatne, jeśli widok dziecka jest tej samej wysokości. W przeciwnym razie będziesz musiał przechowywać jakąś wartość „minimumHeight” nad wszystkimi dziećmi, z którymi sprawdzasz, a nawet wtedy możesz nie chcieć, aby puste widoki były widoczne pod widokami mniejszych dzieci.
Samo rozwiązanie nie jest jednak dla mnie wystarczające, ale dzieje się tak, ponieważ moje elementy potomne są listViews, a ich zmierzona wysokość nie jest poprawnie obliczana.
źródło
Mam wersję WrapContentHeightViewPager, która działała poprawnie przed API 23, która zmieni rozmiar podstawy wysokości widoku rodzica na wybranym wybranym widoku potomnym.
Po aktualizacji do API 23 przestał działać. Okazuje się, że stare rozwiązanie wykorzystywało
getChildAt(getCurrentItem())
bieżący widok potomny do pomiaru, który nie działa. Zobacz rozwiązanie tutaj: https://stackoverflow.com/a/16512217/1265583Poniżej działa z API 23:
źródło
requestLayout()
więc wysokość jest dostosowywana podczas przechodzenia od jednej karty do drugiej. Czy pamiętasz, dlaczegosuper
trzeba zadzwonić dwa razy? Zauważyłem, że inaczej to nie zadziała.Poniższy kod jest jedyną rzeczą, która zadziałała dla mnie
1. Użyj tej klasy do zadeklarowania programu HeightWrappingViewPager:
2. Wstaw pager widoku zawijania wysokości do pliku xml:
3. Zadeklaruj pager widoku:
źródło
Edytuję odpowiedź cybergen dla make viewpager, aby zmienić wysokość w zależności od wybranego elementu Klasa jest taka sama jak cybergena, ale dodałem wektor liczb całkowitych, który jest wszystkimi wysokościami widoków potomnych viewpager i możemy uzyskać do niego dostęp, gdy zmiana strony spowoduje aktualizację wysokości
To jest klasa:
Następnie w swojej działalności dodaj OnPageChangeListener
A oto xml:
W razie potrzeby popraw mój angielski
źródło
heights
Lista może zwiększyć nieskończoność.measure
będzie wywoływane wielokrotnie. Może zwiększyć listę wysokości. Inną sytuacją jest to, że użytkownik może wywołaćrequestLayout
(lubsetLayoutParams
metodę, dokładnie tak jak to zrobiłeś) dla tego viewPager ręcznie, również będzie mierzył wiele razy.Jeśli
ViewPager
używasz dzieckaScrollView
ORAZ maPagerTitleStrip
dziecko, musisz użyć niewielkiej modyfikacji wspaniałych już udzielonych odpowiedzi. Dla odniesienia mój XML wygląda następująco:W swoim
onMeasure
musisz DODAĆ zmierzone WysokośćPagerTitleStrip
jeśli zostanie znaleziony. W przeciwnym razie jego wysokość nie będzie brana pod uwagę jako największa ze wszystkich dzieci, nawet jeśli zajmuje ona dodatkowe miejsce.Mam nadzieję, że to pomaga komuś innemu. Przepraszam, że to trochę hack ...
źródło
Większość rozwiązań, które tu widzę, wydają się wykonywać podwójny pomiar: najpierw mierząc widoki dziecka, a następnie wywołując
super.onMeasure()
Wymyśliłem niestandardowy,
WrapContentViewPager
który jest bardziej wydajny, dobrze współpracuje z RecyclerView i FragmentMożesz sprawdzić wersję demo tutaj:
github / ssynhtn / WrapContentViewPager
i kod klasy tutaj: WrapContentViewPager.java
źródło
Mam podobny (ale bardziej złożony scenariusz). Mam okno dialogowe, które zawiera ViewPager.
Jedna ze stron podrzędnych jest krótka i ma wysokość statyczną.
Kolejna strona podrzędna powinna zawsze być tak wysoka, jak to możliwe.
Kolejna strona potomna zawiera ScrollView, a strona (a zatem całe okno dialogowe) powinna WRAP_CONTENT, jeśli zawartość ScrollView nie potrzebuje pełnej wysokości dostępnej dla okna dialogowego.
Żadna z istniejących odpowiedzi nie zadziałała całkowicie dla tego konkretnego scenariusza. Trzymaj się - to wyboista jazda.
Ogromne podziękowania dla @Raanan za kod do pomiaru widoków i pomiaru wysokości dekoru. Wystąpiły problemy z jego biblioteką - animacja się zacięła i myślę, że mój ScrollView nie przewinąłby się, gdy wysokość okna dialogowego była wystarczająco krótka, aby tego wymagać.
źródło
w moim przypadku dodanie
clipToPadding
rozwiązało problem.Twoje zdrowie!
źródło
W moim przypadku dodanie Androida: fillViewport = "true" rozwiązało problem
źródło
W moim przypadku potrzebowałem przeglądarki z zawartością wrap_content dla aktualnie wybranego elementu i animacji podczas stosowania rozmiaru. Poniżej możesz zobaczyć moją implementację. Czy ktoś może się przydać.
Dodaj attrs.xml w projekcie:
I użyć:
źródło
ViewPager zmienia rozmiar tylko do aktualnie widocznych elementów potomnych (nie jest to największy z rzeczywistych elementów potomnych)
Pomysł z https://stackoverflow.com/a/56325869/4718406
}
źródło
Zmierz wysokość ViewPager:
wywołanie setPrimaryView (widok) :
źródło
Podaj układ nadrzędny ViewPager jako
NestedScrollView
Nie zapomnij ustawić
android:fillViewport="true"
Spowoduje to rozciągnięcie widoku przewijania i zawartości jego dziecka do wypełnienia okienka ekranu.
https://developer.android.com/reference/android/widget/ScrollView.html#attr_android:fillViewport
źródło
Możesz przejść do ViewPager2. Jest to zaktualizowana wersja ViewPager. Robi to samo co ViewPager, ale w bardziej inteligentny i wydajny sposób. ViewPager2 zawiera wiele nowych funkcji. Oczywiście problem zawijania treści został rozwiązany przez ViewPager2.
Z dokumentów Androida: „ViewPager2 zastępuje ViewPager, rozwiązując większość problemów związanych z jego poprzednikiem, w tym obsługę układu od prawej do lewej, orientację pionową, modyfikowalne kolekcje fragmentów itp.”
Polecam ten artykuł dla początkujących:
https://medium.com/google-developer-experts/exploring-the-view-pager-2-86dbce06ff71
źródło