12
votes

Comment ajuster la hauteur d'Android ViewPager2 à la hauteur de l'élément actuel?

Cette question concerne la nouvelle classe ViewPager2 .

Il y a une question similaire pour l'ancien ViewPager , mais la solution nécessite d'étendre ViewPager . Cependant, ViewPager2 est définitif et ne peut donc pas être étendu.

Dans ma situation, j'ai un ViewPager2 qui contient trois fragments différents. L'un de ces fragments est beaucoup plus grand que les deux autres, ce qui signifie que lorsque vous glissez vers l'un des fragments les plus courts, il y a beaucoup d'espace vide. Alors, comment envelopper efficacement le ViewPager2 à la hauteur du fragment actuel?


4 commentaires

Veuillez publier votre code et vos captures d'écran


L'avez-vous compris?


@Kimble Pas encore. :-(


Voir également stackoverflow.com/a/60385555/2914140 et reddit.com/r/androiddev/comments/dl4ug3/… .


5 Réponses :


0
votes

Pour moi, les paramètres de mise en page recyclerview de viewpager2 résolvent ce problème.

Essayer

RecyclerView recyclerView = (RecyclerView) viewPager.getChildAt(0);
recyclerView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));

et définir les paramètres de mise en page de recyclerview

<androidx.viewpager2.widget.ViewPager2
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />


1 commentaires

Merci, mais cela n'a pas fonctionné pour moi. Toutes mes pages ViewPager2 ont disparu avec ce code. Cela dit, mes pages sont des vues maintenant (plutôt que des fragments), alors peut-être que votre réponse pourrait fonctionner pour quelqu'un d'autre.



5
votes

Je ne suis pas du tout satisfait de cette solution de contournement, mais elle résout les problèmes de rendu que j'ai rencontrés en essayant d'utiliser ViewPager2 avec des fragments de différentes hauteurs. Cela ralentira évidemment le rendu et consommera plus de mémoire.

myStupidViewPager2.offscreenPageLimit = fragments.size


3 commentaires

viewPager.setOffscreenPageLimit(3); N'a pas travaillé pour moi. Cependant, mes pages sont maintenant des vues (plutôt que des fragments), donc peut-être que votre réponse pourrait fonctionner pour quelqu'un d'autre.


où appelez-vous ça?


Bonne idée mais ne fonctionne pas avec des éléments chargés paresseusement (comme la pagination)



1
votes

J'ai trouvé une réponse à cette question où j'accède à l'enfant via son adaptateur, car lorsque vous accédez à l'enfant à une position donnée plutôt qu'à l'index Zer0, la vue est nulle.

    class ViewPager2PageChangeCallback() : ViewPager2.OnPageChangeCallback() {
        override fun onPageSelected(position: Int) {
            val view = (pager.adapter as pagerAdapter).getViewAtPosition(position)
            view?.let {
                updatePagerHeightForChild(view, pager)
            }
        }
    }

    private fun updatePagerHeightForChild(view: View, pager: ViewPager2) {
        view.post {
            val wMeasureSpec =
                View.MeasureSpec.makeMeasureSpec(view.width, View.MeasureSpec.EXACTLY)
            val hMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
            view.measure(wMeasureSpec, hMeasureSpec)

            if (pager.layoutParams.height != view.measuredHeight) {
                pager.layoutParams = (pager.layoutParams)
                    .also { lp ->
                        lp.height = view.measuredHeight
                    }
            }
        }
    }

   pager.offscreenPageLimit = 1            
   pagerpager.registerOnPageChangeCallback(ViewPager2PageChangeCallback())

     override fun onDestroy() {
        super.onDestroy()
        pager.unregisterOnPageChangeCallback(ViewPager2PageChangeCallback())
    }

 

    class OrderDetailsPager(
    private val arrayList: ArrayList<Fragment>,
    fragmentManger: FragmentManager,
    lifecycle: Lifecycle
    ) : FragmentStateAdapter(fragmentManger, lifecycle) {
    override fun createFragment(position: Int): Fragment {
        return arrayList[position]
    }

    override fun getItemCount(): Int {
        return arrayList.size
    }

    fun getViewAtPosition(position: Int): View? {
        return arrayList[position].view
    }
}


12 commentaires

cela ne fonctionne pas, qu'est-ce que getViewAtPosition et pagerAdapter? Le code est vraiment mauvais.


getViewAtPosition en tant que méthode ajoutée à votre pagerAdapter (View pager2 Adapter)


@AssemMahrous pourriez-vous s'il vous plaît mettre à jour l'exemple de code pour afficher également getViewAtPosition et pagerAdapter, car je suis également perplexe par la provenance de ceux-ci.


j'ai édité le code et ajouté l'adaptateur de téléavertisseur @sphrak


à peu près sûr que cela ne fonctionne pas pour viewpager2 FragmentStateAdapter est pour viewpager et il est déjà obsolète


@Fugogugo Non, il existe dans viewpager2 dans le package androidx.viewpager2.adapter


Pourquoi créez-vous à nouveau un rappel dans onDestroy : pager.unregisterOnPageChangeCallback(ViewPager2PageChangeCal‌​lback()) ? Ha, c'est drôle.


getViewAtPosition peut être inconnu.


@AssemMahrous view.measuredHeight est toujours égal à zéro


@praj ajoutez-vous les fragments à l'adaptateur et à l'ensemble de la limite d'écran ??


@AssemMahrous Oui, j'ai ajouté des fragments à l'adaptateur et à offscreenPageLimit à 3. Lors du premier chargement de la vue, j'obtiens une valeur pour measureHeight. La commutation entre la valeur de tabulation est remise à zéro.


arrayList [position] .view est parfois nul car la vue n'a pas encore été rendue, donc la solution ne fonctionne pas dans tous les cas



0
votes

J'ai eu le même problème, ViewPager2 était dans ScrollView, qui est sous TabLayout. Après avoir parcouru les onglets, la hauteur de ScrollView est devenue égale à la hauteur de la hauteur maximale du fragment. Le problème a été résolu en transférant le ScrollView vers le fragment.


0 commentaires

2
votes

La solution consiste à ajouter ce qui suit dans chaque fragment qui fait partie du ViewPager2 :

override fun onResume() {
   super.onResume()
   binding.root.requestLayout()
}

binding.root est de ViewBinding / DataBinding mais il est le conteneur principal de votre mise en page, par exemple ConstraintLayout , LinearLayout , etc.


0 commentaires