Ich habe einen einfachen ViewPager eingerichtet, der eine ImageView mit einer Höhe von 200 dp auf jeder Seite hat.
Hier ist mein 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);
Trotz der als wrap_content festgelegten Höhe füllt der Pager immer den Bildschirm aus, obwohl die Bildansicht nur 200 dp beträgt. Ich habe versucht, die Höhe des Pagers durch "200" zu ersetzen, aber das führt zu unterschiedlichen Ergebnissen bei mehreren Auflösungen. Ich kann diesem Wert kein "dp" hinzufügen. Wie füge ich dem Layout des Pagers 200 dp hinzu?
Antworten:
Wenn Sie
ViewPager
Folgendes wie folgt überschreiben, wird die Größe des größten Kindes erreicht, das es derzeit hat.quelle
Eine andere allgemeinere Lösung besteht darin,
wrap_content
einfach an die Arbeit zu gehen.Ich habe erweitert
ViewPager
, um zu überschreibenonMeasure()
. Die Höhe wird um die erste untergeordnete Ansicht gewickelt. Dies kann zu unerwarteten Ergebnissen führen, wenn die untergeordneten Ansichten nicht genau dieselbe Höhe haben. Dafür kann die Klasse leicht erweitert werden, um beispielsweise die Größe der aktuellen Ansicht / Seite zu animieren. Aber das habe ich nicht gebraucht.Sie können diesen ViewPager in Ihren XML-Layouts genau wie den ursprünglichen ViewPager verwenden:
Vorteil: Mit diesem Ansatz können Sie den ViewPager in jedem Layout einschließlich RelativeLayout verwenden, um andere UI-Elemente zu überlagern.
Ein Nachteil bleibt: Wenn Sie Ränder verwenden möchten, müssen Sie zwei verschachtelte Layouts erstellen und dem inneren die gewünschten Ränder geben.
Hier ist der Code:
quelle
Ich habe meine Antwort auf Daniel López Lacalle und diesen Beitrag http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ gestützt . Das Problem mit Daniels Antwort ist, dass meine Kinder in einigen Fällen eine Größe von Null hatten. Die Lösung bestand leider darin, zweimal zu messen.
Auf diese Weise können Sie auch eine Höhe auf dem ViewPager festlegen, wenn Sie dies möchten oder nur wrap_content.
quelle
scaleType
und in ähnlicher Weise,layout_width=match_parent
wie auchlayout_height=wrap_content
? dort fehlen etwa 20dp.// super has to be called in the beginning so the child views can be initialized.
<----- DAS war der Grund, musste es am Anfang und am Ende der onMeasure-Funktion aufrufen. Yippiii, heute virtuelle High Fives auf mich!Ich habe gerade eine sehr ähnliche Frage dazu beantwortet und habe diese zufällig gefunden, als ich nach einem Link gesucht habe, um meine Behauptungen zu stützen, also viel Glück :)
Meine andere Antwort:
Der ViewPager unterstützt nicht,
wrap_content
da (normalerweise) nie alle untergeordneten Elemente gleichzeitig geladen werden und daher keine geeignete Größe erhalten werden kann (die Option wäre, einen Pager zu haben, dessen Größe sich bei jedem Wechsel ändert Seite).Sie können jedoch eine genaue Abmessung (z. B. 150 dp) festlegen und
match_parent
funktionieren auch.Sie können die Dimensionen auch dynamisch aus Ihrem Code heraus ändern, indem Sie das
height
Attribut -attribute in seinem Code ändernLayoutParams
.Für Ihre Anforderungen können Sie den ViewPager in einer eigenen XML-Datei erstellen, wobei die layout_height auf 200 dp festgelegt ist, und dann in Ihrem Code, anstatt einen neuen ViewPager von Grund auf neu zu erstellen, diese XML-Datei aufblasen:
quelle
layout_height
set towrap_content
, ist jedoch noch schlimmer, da die einfache Problemumgehung zum Einrichten auf einen festen Betrag nicht funktioniert.Mit der Antwort von Daniel López Localle habe ich diese Klasse in Kotlin erstellt. Hoffe es spart dir mehr Zeit
quelle
Ich habe dieses Problem bereits in mehreren Projekten gesehen und hatte nie eine vollständige Lösung. Deshalb habe ich ein WrapContentViewPager-Github-Projekt als direkten Ersatz für ViewPager erstellt.
https://github.com/rnevet/WCViewPager
Die Lösung wurde von einigen der Antworten hier inspiriert, verbessert sich jedoch:
Aktualisiert für die Support-Bibliothek Version 24, die die vorherige Implementierung beschädigt hat.
quelle
Ich bin gerade auf das gleiche Problem gestoßen. Ich hatte einen ViewPager und wollte eine Anzeige auf der Schaltfläche anzeigen. Die Lösung, die ich gefunden habe, bestand darin, den Pager in eine RelativeView zu integrieren und sein layout_above auf die Ansichts-ID zu setzen, die ich darunter sehen möchte. das hat bei mir funktioniert.
Hier ist mein Layout XML:
quelle
Ich bin auch auf dieses Problem gestoßen, aber in meinem Fall hatte ich ein Problem,
FragmentPagerAdapter
das dieViewPager
Seiten lieferte . Das Problem, das ich hatte, war dasonMeasure()
desViewPager
wurde vor einem der angerufenFragments
erstellt wurde (und sich daher nicht richtig dimensionieren konnte).Nach einigem Ausprobieren stellte ich fest, dass die
finishUpdate()
Methode des FragmentPagerAdapter aufgerufen wird, nachdem dieFragments
(voninstantiateItem()
inFragmentPagerAdapter
) und auch nach / während des Bildlaufs initialisiert wurden . Ich habe eine kleine Schnittstelle gemacht:was ich in meine übergebe
FragmentPagerAdapter
und rufe:was mir wiederum erlaubt,
setVariableHeight()
auf meineCustomViewPager
Implementierung zurückzugreifen:Ich bin mir nicht sicher, ob es der beste Ansatz ist. Ich würde mich über Kommentare freuen, wenn Sie denken, dass es gut / schlecht / böse ist, aber es scheint in meiner Implementierung ziemlich gut zu funktionieren :)
Hoffe das hilft jemandem da draußen!
BEARBEITEN: Ich habe vergessen,
requestLayout()
nach dem Aufruf ein hinzuzufügensuper.measure()
(andernfalls wird die Ansicht nicht neu gezeichnet).Ich habe auch vergessen, die Polsterung der Eltern zur endgültigen Höhe hinzuzufügen.
Ich habe auch die ursprüngliche Breite / Höhe MeasureSpecs beibehalten, um bei Bedarf eine neue zu erstellen. Habe den Code entsprechend aktualisiert.
Ein weiteres Problem, das ich hatte, war, dass es sich in einem nicht richtig dimensionierte
ScrollView
und feststellte, dass der Täter das Kind mitMeasureSpec.EXACTLY
statt maßMeasureSpec.UNSPECIFIED
. Aktualisiert, um dies widerzuspiegeln.Diese Änderungen wurden alle dem Code hinzugefügt. Sie können den Verlauf überprüfen, um die alten (falschen) Versionen anzuzeigen, wenn Sie möchten.
quelle
Eine andere Lösung besteht darin, die
ViewPager
Höhe entsprechend der aktuellen Seitenhöhe zu aktualisierenPagerAdapter
. Angenommen, Sie erstellen IhreViewPager
Seiten folgendermaßen:Wo
mPages
wird eine interne Liste vonPageInfo
Strukturen dynamisch zum hinzugefügtPagerAdapter
undCustomImageView
ist nur regelmäßigImageView
mit ÜberschreibungonMeasure()
ist, bei der die Höhe entsprechend der angegebenen Breite festgelegt wird und das Bildseitenverhältnis beibehalten wird.Sie können die
ViewPager
Höhe in dersetPrimaryItem()
Methode erzwingen :Beachten Sie die
Math.max(height, 1)
. Dies behebt einen lästigen Fehler, derViewPager
die angezeigte Seite nicht aktualisiert (sie wird leer angezeigt), wenn die vorherige Seite eine Höhe von Null hat (dh in der Null nicht zeichnbar istCustomImageView
), wobei jede ungerade zwischen zwei Seiten hin und her wischt .quelle
item.mImageView.measure(..)
, um die richtigen Dimensionen in dengetMeasuredXXX()
Methoden zu erhalten.Wenn Sie statischen Inhalt im Viewpager verwenden und keine ausgefallene Animation wünschen, können Sie den folgenden View-Pager verwenden
quelle
quelle
Aus dem Quellcode der Popcorn-Zeit-Android-App habe ich diese Lösung gefunden, die die Größe des Viewpagers mit einer schönen Animation dynamisch an die Größe des aktuellen Kindes anpasst.
https://git.popcorntime.io/popcorntime/android/blob/5934f8d0c8fed39af213af4512272d12d2efb6a6/mobile/src/main/java/pct/droid/widget/WrappingViewPager.java
quelle
Für den Fall, dass Sie ViewPager benötigen, der seine Größe an jedes Kind anpasst , nicht nur an das größte, habe ich einen Code geschrieben, der dies tut. Beachten Sie, dass bei dieser Änderung keine Animation vorhanden ist (in meinem Fall nicht erforderlich).
android: minHeight Flag wird ebenfalls unterstützt.
quelle
Verbesserte Antwort von Daniel López Lacalle , umgeschrieben in Kotlin :
quelle
Ich bin auf dasselbe Problem gestoßen, und ich musste den ViewPager auch um seinen Inhalt wickeln lassen, wenn der Benutzer zwischen den Seiten blätterte. Unter Verwendung der obigen Antwort von cybergen habe ich die onMeasure-Methode wie folgt definiert:
Auf diese Weise legt die onMeasure-Methode die Höhe der aktuellen Seite fest, die vom ViewPager angezeigt wird.
quelle
Nichts von dem oben vorgeschlagenen hat für mich funktioniert. Mein Anwendungsfall besteht darin, 4 benutzerdefinierte ViewPager zu haben
ScrollView
. Die Oberseite von ihnen wird basierend auf dem Seitenverhältnis gemessen und der Rest hat geradelayout_height=wrap_content
. Ich habe Cybergen , Daniel López Lacalle Lösungen ausprobiert . Keiner von ihnen arbeitet voll für mich.Ich vermute, warum Cybergen auf Seite> 1 nicht funktioniert, weil es die Höhe des Pagers basierend auf Seite 1 berechnet, die ausgeblendet ist, wenn Sie weiter scrollen.
Sowohl Cybergen als auch Daniel López Lacalle haben in meinem Fall ein seltsames Verhalten: 2 von 3 sind in Ordnung geladen und 1 zufällige Größe ist 0. Erscheint,
onMeasure
der aufgerufen wurde, bevor Kinder bevölkert wurden. Also habe ich mir eine Mischung aus diesen 2 Antworten und meinen eigenen Korrekturen ausgedacht:Die Idee ist,
ViewPager
die Abmessungen der Kinder berechnen zu lassen und die berechnete Höhe der ersten Seite in den Layoutparametern des zu speichernViewPager
. Vergessen Sie nicht, die Layouthöhe des Fragments auf einzustellen,wrap_content
da Sie sonst height = 0 erhalten können. Ich habe dieses verwendet:Bitte beachten Sie, dass diese Lösung hervorragend funktioniert, wenn alle Ihre Seiten dieselbe Höhe haben . Andernfalls müssen Sie die
ViewPager
Höhe basierend auf dem aktuell aktiven Kind neu berechnen . Ich brauche es nicht, aber wenn Sie die Lösung vorschlagen, würde ich die Antwort gerne aktualisieren.quelle
Für Benutzer mit diesem Problem und der Codierung für Xamarin Android in C # ist dies möglicherweise auch eine schnelle Lösung:
Dies ist vor allem dann nützlich, wenn die Ansichten Ihres Kindes gleich hoch sind. Andernfalls müssten Sie für alle untergeordneten Elemente, gegen die Sie prüfen, eine Art "MinimumHeight" -Wert speichern, und selbst dann möchten Sie möglicherweise keine leeren Bereiche unter Ihren kleineren untergeordneten Ansichten sichtbar machen.
Die Lösung selbst reicht mir zwar nicht aus, aber das liegt daran, dass meine untergeordneten Elemente listViews sind und ihre MeasuredHeight anscheinend nicht korrekt berechnet wird.
quelle
Ich habe eine Version von WrapContentHeightViewPager, die vor API 23 ordnungsgemäß funktioniert hat und deren Größe die Höhenbasis der übergeordneten Ansicht auf der aktuell ausgewählten untergeordneten Ansicht ändert.
Nach dem Upgrade auf API 23 funktionierte es nicht mehr. Es stellt sich heraus, dass die alte Lösung verwendet wurde
getChildAt(getCurrentItem())
, um die aktuelle untergeordnete Ansicht zu messen, was nicht funktioniert. Die Lösung finden Sie hier: https://stackoverflow.com/a/16512217/1265583Unten funktioniert mit API 23:
quelle
requestLayout()
damit die Höhe angepasst wird, wenn wir von einer Registerkarte zur nächsten wechseln . Erinnerst du dich, warumsuper
zweimal angerufen werden muss? Mir ist aufgefallen, dass es sonst nicht funktioniert.Der folgende Code ist das einzige, was für mich funktioniert hat
1. Deklarieren Sie mit dieser Klasse einen HeightWrappingViewPager:
2. Fügen Sie den Pager für die Höhenumbruchansicht in Ihre XML-Datei ein:
3. Deklarieren Sie Ihren View Pager:
quelle
Ich bearbeite die Antwort von cybergen, damit der Viewpager die Höhe abhängig vom ausgewählten Element ändert. Die Klasse ist dieselbe wie die von cybergen, aber ich habe einen Vektor von Ganzzahlen hinzugefügt, der die Höhe aller untergeordneten Ansichten des Viewpagers darstellt, und wir können darauf zugreifen, wenn die Seite geändert wird, um die Höhe zu aktualisieren
Das ist die Klasse:
Fügen Sie dann in Ihrer Aktivität einen OnPageChangeListener hinzu
Und hier ist xml:
Bitte korrigieren Sie gegebenenfalls mein Englisch
quelle
heights
Liste kann die Unendlichkeit erhöhen.measure
würde der Anruf daher mehrmals aufgerufen werden. Es kann die Höhenliste erhöhen. Eine andere Situation ist, dass der Benutzer diesen viewPager manuell aufruftrequestLayout
(oder einesetLayoutParams
Methode, genau wie Sie es getan haben), und auch mehrere Male misst.Wenn das, das
ViewPager
Sie verwenden, ein Kind einesScrollView
UND ist und einPagerTitleStrip
Kind hat, müssen Sie eine geringfügige Modifikation der bereits bereitgestellten großartigen Antworten verwenden. Als Referenz sieht mein XML folgendermaßen aus:In Ihrem müssen
onMeasure
Sie die gemessene Höhe der hinzufügenPagerTitleStrip
, wenn man gefunden wird. Andernfalls wird seine Größe nicht als die größte Größe aller Kinder angesehen, obwohl er zusätzlichen Platz beansprucht.Hoffe das hilft jemand anderem. Tut mir leid, dass es ein bisschen ein Hack ist ...
quelle
Die meisten Lösungen, die ich hier sehe, scheinen eine Doppelmessung durchzuführen: zuerst die untergeordneten Ansichten messen und dann die aufrufen
super.onMeasure()
Ich habe mir einen Benutzer ausgedacht
WrapContentViewPager
, der effizienter ist und gut mit RecyclerView und Fragment funktioniertSie können die Demo hier überprüfen:
github / ssynhtn / WrapContentViewPager
und den Code der Klasse hier: WrapContentViewPager.java
quelle
Ich habe ein ähnliches (aber komplexeres Szenario). Ich habe einen Dialog, der einen ViewPager enthält.
Eine der untergeordneten Seiten ist kurz und hat eine statische Höhe.
Eine andere untergeordnete Seite sollte immer so groß wie möglich sein.
Eine andere untergeordnete Seite enthält eine ScrollView, und die Seite (und damit der gesamte Dialog) sollte WRAP_CONTENT sein, wenn der ScrollView-Inhalt nicht die volle Höhe benötigt, die dem Dialog zur Verfügung steht.
Keine der vorhandenen Antworten funktionierte vollständig für dieses spezielle Szenario. Warte - es ist eine holprige Fahrt.
Vielen Dank an @Raanan für den Code zum Messen von Ansichten und zum Messen der Dekorhöhe. Ich hatte Probleme mit seiner Bibliothek - die Animation stotterte und ich glaube, meine ScrollView würde nicht scrollen, wenn die Höhe des Dialogfelds kurz genug war, um es zu erfordern.
quelle
In meinem Fall hat das Hinzufügen
clipToPadding
das Problem gelöst.Prost!
quelle
Ich mein Fall Hinzufügen von Android: fillViewport = "true" löste das Problem
quelle
In meinem Fall benötigte ich beim Anwenden der Größe einen Viewpager mit einem wrap_content für das aktuell ausgewählte Element und die Animation. Unten sehen Sie meine Implementierung. Kann jemand nützlich sein.
Fügen Sie attrs.xml im Projekt hinzu:
Und benutze:
quelle
Dieser ViewPager ändert nur die Größe der aktuell sichtbaren Kinder (nicht das größte seiner tatsächlichen Kinder).
Die Idee von https://stackoverflow.com/a/56325869/4718406
}}
quelle
Messen Sie die Höhe von ViewPager:
Rufen Sie setPrimaryView (View) auf:
quelle
Geben Sie das übergeordnete Layout von ViewPager als an
NestedScrollView
Vergiss nicht zu setzen
android:fillViewport="true"
Dadurch werden die Bildlaufansicht und der Inhalt des untergeordneten Elements erweitert, um das Ansichtsfenster zu füllen.
https://developer.android.com/reference/android/widget/ScrollView.html#attr_android:fillViewport
quelle
Sie können zu ViewPager2 wechseln. Es ist eine aktualisierte Version von ViewPager. Es funktioniert genauso wie ViewPager, jedoch intelligenter und effizienter. ViewPager2 bietet eine Vielzahl neuer Funktionen. Natürlich wurde das Problem mit dem Wrap-Inhalt von ViewPager2 behoben.
Aus Android-Dokumenten: "ViewPager2 ersetzt ViewPager und behebt die meisten Probleme des Vorgängers, einschließlich Unterstützung des Layouts von rechts nach links, vertikale Ausrichtung, modifizierbare Fragmentsammlungen usw."
Ich empfehle diesen Artikel für Anfänger:
https://medium.com/google-developer-experts/exploring-the-view-pager-2-86dbce06ff71
quelle