J'ai installé un simple ViewPager qui a une ImageView avec une hauteur de 200dp sur chaque page.
Voici mon téléavertisseur:
pager = new ViewPager(this);
pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
pager.setBackgroundColor(Color.WHITE);
pager.setOnPageChangeListener(listener);
layout.addView(pager);
Malgré la hauteur définie comme wrap_content, le pager remplit toujours l'écran même si la vue d'image n'est que de 200dp. J'ai essayé de remplacer la hauteur du téléavertisseur par "200" mais cela me donne des résultats différents avec plusieurs résolutions. Je ne peux pas ajouter "dp" à cette valeur. Comment ajouter 200dp à la disposition du pager?
Réponses:
En remplaçant la mesure de votre
ViewPager
comme suit, elle atteindra la taille du plus grand enfant qu'elle a actuellement.la source
Une autre solution plus générique consiste à se
wrap_content
contenter de travailler.J'ai étendu
ViewPager
pour remplaceronMeasure()
. La hauteur est enroulée autour de la première vue enfant. Cela peut entraîner des résultats inattendus si les vues enfant ne sont pas exactement de la même hauteur. Pour cela, la classe peut être facilement étendue pour, disons, animer à la taille de la vue / page actuelle. Mais je n'en avais pas besoin.Vous pouvez utiliser ce ViewPager dans vos présentations XML comme le ViewPager d'origine:
Avantage: Cette approche permet d'utiliser le ViewPager dans n'importe quelle mise en page, y compris RelativeLayout pour superposer d'autres éléments d'interface utilisateur.
Un inconvénient demeure: si vous souhaitez utiliser des marges, vous devez créer deux dispositions imbriquées et donner à l'intérieur les marges souhaitées.
Voici le code:
la source
J'ai basé ma réponse sur Daniel López Lacalle et ce post http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ . Le problème avec la réponse de Daniel est que dans certains cas, mes enfants avaient une hauteur de zéro. La solution était malheureusement de mesurer deux fois.
Cela vous permet également de définir une hauteur sur le ViewPager si vous le souhaitez ou simplement wrap_content.
la source
scaleType
et de même,layout_width=match_parent
ainsi quelayout_height=wrap_content
? il y a comme 20dp manquant là-bas.// super has to be called in the beginning so the child views can be initialized.
<----- C'ÉTAIT la raison, a dû l'appeler au début et à la fin de la fonction onMeasure. Yippiii, high fives virtuels sur moi aujourd'hui!Je venais de répondre à une question très similaire à ce sujet, et je l'ai trouvé en recherchant un lien pour sauvegarder mes réclamations, alors vous avez de la chance :)
Mon autre réponse:
le ViewPager ne prend pas en charge
wrap_content
car il (généralement) ne charge jamais tous ses enfants en même temps, et ne peut donc pas obtenir une taille appropriée (l'option serait d'avoir un pager qui change de taille à chaque fois que vous avez changé page).Vous pouvez cependant définir une dimension précise (par exemple 150dp) et
match_parent
fonctionne également.Vous pouvez également modifier les dimensions dynamiquement à partir de votre code en modifiant l'
height
attribut -attitude dans sonLayoutParams
.Pour vos besoins, vous pouvez créer le ViewPager dans son propre fichier xml, avec le layout_height défini sur 200dp, puis dans votre code, plutôt que de créer un nouveau ViewPager à partir de zéro, vous pouvez gonfler ce fichier xml:
la source
layout_height
set towrap_content
, mais c'est encore pire car la solution de contournement simple pour la configurer à un montant fixe ne fonctionne pas.En utilisant la réponse de Daniel López Localle , j'ai créé cette classe dans Kotlin. J'espère que cela vous fera gagner plus de temps
la source
J'ai déjà rencontré ce problème dans plusieurs projets et je n'ai jamais eu de solution complète. J'ai donc créé un projet github WrapContentViewPager en remplacement sur place de ViewPager.
https://github.com/rnevet/WCViewPager
La solution a été inspirée par certaines des réponses ici, mais améliore:
Mis à jour pour la bibliothèque de support version 24 qui a cassé l'implémentation précédente.
la source
Je suis juste tombé sur le même problème. J'avais un ViewPager et je voulais afficher une annonce au bouton de celui-ci. La solution que j'ai trouvée consistait à placer le pager dans un RelativeView et à définir son layout_above sur l'ID de vue que je veux voir en dessous. cela a fonctionné pour moi.
voici ma mise en page XML:
la source
J'ai également rencontré ce problème, mais dans mon cas, j'avais un
FragmentPagerAdapter
qui fournissait leViewPager
avec ses pages. Le problème que j'ai eu était queonMeasure()
le aViewPager
été appelé avant laFragments
création de l'un (et ne pouvait donc pas se dimensionner correctement).Après un peu d'essais et d'erreurs, j'ai trouvé que la
finishUpdate()
méthode de FragmentPagerAdapter est appelée aprèsFragments
avoir été initialisée (à partirinstantiateItem()
de laFragmentPagerAdapter
) et également après / pendant le défilement de la page. J'ai fait une petite interface:que je passe dans mon
FragmentPagerAdapter
et appelle:ce qui me permet à mon tour de faire appel
setVariableHeight()
à maCustomViewPager
mise en œuvre:Je ne suis pas sûr que ce soit la meilleure approche, j'adorerais les commentaires si vous pensez que c'est bon / mauvais / mauvais, mais cela semble fonctionner assez bien dans ma mise en œuvre :)
J'espère que cela aide quelqu'un là-bas!
EDIT: J'ai oublié d'ajouter un
requestLayout()
après l'appelsuper.measure()
(sinon il ne redessine pas la vue).J'ai également oublié d'ajouter le rembourrage du parent à la hauteur finale.
J'ai également abandonné la conservation de la largeur / hauteur originale MeasureSpecs en faveur de la création d'une nouvelle au besoin. Avoir mis à jour le code en conséquence.
Un autre problème que j'avais était qu'il ne se dimensionnerait pas correctement dans un
ScrollView
et a trouvé que le coupable mesurait l'enfant avecMeasureSpec.EXACTLY
au lieu deMeasureSpec.UNSPECIFIED
. Mis à jour pour refléter cela.Ces modifications ont toutes été ajoutées au code. Vous pouvez consulter l'historique pour voir les anciennes versions (incorrectes) si vous le souhaitez.
la source
Une autre solution consiste à mettre à jour la
ViewPager
hauteur en fonction de la hauteur de page actuelle dans sonPagerAdapter
. En supposant que vous créez vosViewPager
pages de cette façon:Où
mPages
est la liste interne desPageInfo
structures ajoutée dynamiquement àPagerAdapter
etCustomImageView
est juste régulièreImageView
avec laonMeasure()
méthode surchargée qui définit sa hauteur en fonction de la largeur spécifiée et conserve le rapport hauteur / largeur de l'image.Vous pouvez forcer la
ViewPager
hauteur dans lasetPrimaryItem()
méthode:Notez le
Math.max(height, 1)
. Cela corrige un bug ennuyeux quiViewPager
ne met pas à jour la page affichée (l'affiche vide), lorsque la page précédente a une hauteur nulle (c'est-à-dire nul dessinable dans leCustomImageView
), chaque balayage impair va et vient entre deux pages.la source
item.mImageView.measure(..)
pour obtenir les bonnes dimensions dans lesgetMeasuredXXX()
méthodes.Lorsque vous utilisez du contenu statique dans le viewpager et que vous ne souhaitez aucune animation de fantaisie, vous pouvez utiliser le view pager suivant
la source
la source
À partir du code source de l'application Android de Popcorn Time, j'ai trouvé cette solution qui ajuste dynamiquement la taille du viseur avec une belle animation en fonction de la taille de l'enfant actuel.
https://git.popcorntime.io/popcorntime/android/blob/5934f8d0c8fed39af213af4512272d12d2efb6a6/mobile/src/main/java/pct/droid/widget/WrappingViewPager.java
la source
Dans le cas où vous avez besoin de ViewPager qui ajuste sa taille à chaque enfant , pas seulement au plus grand, j'ai écrit un morceau de code qui le fait. Notez qu'il n'y a pas d'animation sur ce changement (pas nécessaire dans mon cas)
android: le drapeau minHeight est également pris en charge.
la source
Amélioration de la réponse de Daniel López Lacalle , réécrite dans Kotlin :
la source
Je suis tombé sur le même problème et j'ai également dû faire en sorte que le ViewPager encapsule son contenu lorsque l'utilisateur faisait défiler les pages. En utilisant la réponse ci-dessus de cybergen, j'ai défini la méthode onMeasure comme suit:
De cette façon, la méthode onMeasure définit la hauteur de la page actuelle affichée par le ViewPager.
la source
Rien de suggéré ci-dessus n'a fonctionné pour moi. Mon cas d'utilisation est d'avoir 4 ViewPagers personnalisés
ScrollView
. Le haut d'eux est mesuré en fonction du rapport d'aspect et le reste a justelayout_height=wrap_content
. J'ai essayé les solutions cybergen , Daniel López Lacalle . Aucun d'eux ne fonctionne pleinement pour moi.Je suppose que cybergen ne fonctionne pas sur la page> 1, car il calcule la hauteur du pager en fonction de la page 1, qui est masqué si vous faites défiler plus loin.
Les suggestions de cybergen et de Daniel López Lacalle ont un comportement étrange dans mon cas: 2 sur 3 sont chargés correctement et 1 au hasard est 0. Apparaît qui a
onMeasure
été appelé avant que les enfants ne soient peuplés. J'ai donc trouvé un mélange de ces 2 réponses + mes propres correctifs:L'idée est de laisser
ViewPager
calculer les dimensions des enfants et d'enregistrer la hauteur calculée de la première page dans les paramètres de mise en page duViewPager
. N'oubliez pas de définir la hauteur de mise en page du fragment surwrap_content
sinon vous pouvez obtenir hauteur = 0. J'ai utilisé celui-ci:Veuillez noter que cette solution fonctionne très bien si toutes vos pages ont la même hauteur . Sinon, vous devez recalculer la
ViewPager
hauteur en fonction de l'enfant actuellement actif. Je n'en ai pas besoin, mais si vous suggérez la solution, je serais heureux de mettre à jour la réponse.la source
Pour les personnes ayant ce problème et codant pour Xamarin Android en C #, cela pourrait également être une solution rapide:
Ceci est principalement utile si les vues de vos enfants sont de la même hauteur. Sinon, vous devrez stocker une sorte de valeur "minimumHeight" sur tous les enfants que vous comparez, et même dans ce cas, vous ne voudrez peut-être pas que des espaces vides soient visibles sous vos vues enfant plus petites.
La solution elle-même n'est cependant pas suffisante pour moi, mais c'est parce que mes éléments enfants sont listViews et leur MeasuredHeight n'est pas calculé correctement, semble-t-il.
la source
J'ai une version de WrapContentHeightViewPager qui fonctionnait correctement avant l'API 23 qui redimensionnera la base de hauteur de la vue parent sur la vue enfant actuelle sélectionnée.
Après la mise à niveau vers API 23, il a cessé de fonctionner. Il s'avère que l'ancienne solution était utilisée
getChildAt(getCurrentItem())
pour obtenir la vue enfant actuelle pour mesurer ce qui ne fonctionne pas. Voir la solution ici: https://stackoverflow.com/a/16512217/1265583Ci-dessous fonctionne avec l'API 23:
la source
requestLayout()
donc la hauteur est ajustée lorsque nous passons d'un onglet à l'autre. Vous rappelez-vous pourquoisuper
doit être appelé deux fois? J'ai remarqué que cela ne fonctionnerait pas autrement.Le code ci-dessous est la seule chose qui a fonctionné pour moi
1. Utilisez cette classe pour déclarer un HeightWrappingViewPager:
2. Insérez le pager de vue d'habillage de hauteur dans votre fichier xml:
3. Déclarez votre téléavertisseur de vue:
la source
Je modifie la réponse de cybergen pour que le viewpager change de hauteur en fonction de l'élément sélectionné.La classe est la même que celle de cybergen, mais j'ai ajouté un vecteur d'entiers qui correspond à toutes les hauteurs de vue enfant du viewpager et nous pouvons y accéder lorsque la page change pour mettre à jour la hauteur
Voici la classe:
Ensuite, dans votre activité, ajoutez un OnPageChangeListener
Et voici xml:
Veuillez corriger mon anglais si nécessaire
la source
heights
liste peut augmenter l'infini.measure
serait donc appelé plusieurs fois. Cela peut augmenter la liste des hauteurs. Une autre situation est que l'utilisateur peut appelerrequestLayout
(ou unesetLayoutParams
méthode, comme vous l'avez fait) pour ce viewPager manuellement, mesurera également plusieurs fois.Si
ViewPager
vous utilisez est un enfant d'unScrollView
ET a unPagerTitleStrip
enfant, vous devrez utiliser une légère modification des bonnes réponses déjà fournies. Pour référence, mon XML ressemble à ceci:Dans votre,
onMeasure
vous devez AJOUTER la hauteur mesurée duPagerTitleStrip
si on en trouve. Sinon, sa hauteur ne sera pas considérée comme la plus grande de tous les enfants, même si elle prend plus de place.J'espère que ceci aide quelqu'un d'autre. Désolé que ce soit un peu un hack ...
la source
La plupart des solutions que je vois ici semblent faire une double mesure: mesurer d'abord les vues des enfants, puis appeler
super.onMeasure()
J'ai trouvé une personnalisation
WrapContentViewPager
plus efficace, qui fonctionne bien avec RecyclerView et FragmentVous pouvez consulter la démo ici:
github / ssynhtn / WrapContentViewPager
et le code de la classe ici: WrapContentViewPager.java
la source
J'ai un scénario similaire (mais plus complexe). J'ai une boîte de dialogue, qui contient un ViewPager.
L'une des pages enfants est courte, avec une hauteur statique.
Une autre page enfant doit toujours être aussi haute que possible.
Une autre page enfant contient un ScrollView, et la page (et donc la boîte de dialogue entière) doit WRAP_CONTENT si le contenu de ScrollView n'a pas besoin de toute la hauteur disponible pour la boîte de dialogue.
Aucune des réponses existantes n'a fonctionné complètement pour ce scénario spécifique. Tenez, c'est un parcours cahoteux.
Un grand merci à @Raanan pour le code pour mesurer les vues et mesurer la hauteur du décor. J'ai rencontré des problèmes avec sa bibliothèque - l'animation a bégayé, et je pense que mon ScrollView ne défilerait pas lorsque la hauteur de la boîte de dialogue était suffisamment courte pour l'exiger.
la source
dans mon cas, l'ajout a
clipToPadding
résolu le problème.À votre santé!
la source
Je mon cas en ajoutant Android: fillViewport = "true" a résolu le problème
la source
Dans mon cas, j'avais besoin d'un viewpager avec un wrap_content pour l'élément et l'animation actuellement sélectionnés lors de l'application de la taille. Ci-dessous, vous pouvez voir ma mise en œuvre. Quelqu'un peut-il être utile?
Ajoutez attrs.xml dans le projet:
Et utilise:
la source
Ce ViewPager ne redimensionne que les enfants visibles actuels (pas le plus grand de ses enfants réels)
L'idée de https://stackoverflow.com/a/56325869/4718406
}
la source
Mesurez la hauteur de ViewPager:
appelez setPrimaryView (Voir):
la source
Donner la disposition parent de ViewPager en tant que
NestedScrollView
N'oubliez pas de régler
android:fillViewport="true"
Cela étendra scrollview et le contenu de son enfant pour remplir la fenêtre.
https://developer.android.com/reference/android/widget/ScrollView.html#attr_android:fillViewport
la source
Vous pouvez basculer vers ViewPager2. Il s'agit d'une version mise à jour de ViewPager. Il fait la même chose que ViewPager mais de manière plus intelligente et efficace. ViewPager2 est livré avec une variété de nouvelles fonctionnalités. Bien sûr, le problème de Wrap Content a été résolu par ViewPager2.
À partir de documents Android: "ViewPager2 remplace ViewPager, abordant la plupart des problèmes de son prédécesseur, y compris la prise en charge de la mise en page de droite à gauche, l'orientation verticale, les collections de fragments modifiables, etc."
Je recommande cet article aux débutants:
https://medium.com/google-developer-experts/exploring-the-view-pager-2-86dbce06ff71
la source