ViewPager's height in Coordinator layout is more than available

前端 未结 3 890
抹茶落季
抹茶落季 2021-01-02 04:45

I have a CoordinatorLayout with a Toolbar and a TabLayout inside the AppBarLayout. Additionally, I have a ViewPager

3条回答
  •  滥情空心
    2021-01-02 05:05

    I've spent a lot of time googling and applying suggested answers, but I've not succeeded, so decided to dive deeper into the problem and find out a complete answer, which I want to share here. Maybe it will help somebody.

    So the problem is that when ViewPager is used with Collapsing Toolbar, the first one doesn't calculate its height properly. And if you want the ViewPager fill all the space to the bottom of the screen, but not more - there is a problem. Just adding layout_marginBottom will not solve the problem because of Collapsing Toolbar will change its height when user scroll.

    So if you want your ViewPager to adapt its height accordingly to Collapsing Toolbar height changes, you need 2 things:

    1. Custom scrolling behavior.
    2. GlobalLayoutListener, which will fix ViewPager height when it's drawn for first time.

    Here they are (written in Kotlin, but it's just a separate file and can be placed into Java project directly):

    import android.app.Activity
    import android.content.Context
    import android.graphics.Point
    import android.support.design.widget.AppBarLayout
    import android.support.design.widget.CoordinatorLayout
    import android.util.AttributeSet
    import android.view.View
    import android.view.ViewGroup
    import android.view.ViewTreeObserver
    
    /**
     * Custom extension of AppBarLayout.ScrollingViewBehavior to deal with ViewPager height
     * in a bunch with Collapsing Toolbar Layout. Works dynamically when AppBar Layout height is changing.
     */
    class ViewPagerScrollingBehavior(context: Context, attributeSet: AttributeSet? = null) :
      AppBarLayout.ScrollingViewBehavior(context, attributeSet) {
    
      override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        val layoutParams = child.layoutParams as CoordinatorLayout.LayoutParams
        layoutParams.height = child.height - (dependency.bottom - child.top)
        child.layoutParams = layoutParams
        child.requestLayout()
        return super.onDependentViewChanged(parent, child, dependency)
      }
    
    }
    
    /**
     * Custom implementation of ViewTreeObserver.OnGlobalLayoutListener to fix the View height
     * in a bunch with Collapsing Toolbar Layout. Works when View is drawn on the screen for first time.
     * To be used with ViewPagerScrollingBehavior.
     */
    class FixHeightGlobalLayoutListener(val activity: Activity, val view: View) : ViewTreeObserver.OnGlobalLayoutListener {
    
      override fun onGlobalLayout() {
        val display = activity.windowManager.defaultDisplay
        val size = Point()
        display.getSize(size)
        val height = size.y
    
        val location = IntArray(2)
        view.getLocationOnScreen(location)
    
        view.post {
          val layoutParams = view.layoutParams as ViewGroup.LayoutParams
          layoutParams.height = height - location[1]
          view.layoutParams = layoutParams
          view.requestLayout()
        }
    
        view.viewTreeObserver.removeOnGlobalLayoutListener(this)
      }
    
    }
    

    And use them in your code:

    1. Add the custom behavior to your ViewPager: app:layout_behavior="your.package.ViewPagerScrollingBehavior"

    2. Add custom OnGlobalLayoutListener to your ViewPager: viewPager.getViewTreeObserver().addOnGlobalLayoutListener(new FixHeightGlobalLayoutListener(this, viewPager));

提交回复
热议问题