ViewPager在协调器布局中的高度不仅仅是可用的

时间:2016-09-28 06:44:59

标签: android android-layout android-viewpager android-coordinatorlayout

我在CoordinatorLayout内有Toolbar TabLayoutAppBarLayout。另外,我在ViewPager内但在CoordinatorLayout之外有一个ViewPager

问题是ViewPager's高度大于实际可用的高度,导致我Fragment的某些观看次数被削减。

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/lightGray"
    android:fitsSystemWindows="true">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar2"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:popupTheme="@style/AppTheme.PopupOverlay"
            app:layout_scrollFlags="scroll|enterAlways"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:scrollbars="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:fillViewport="false"/>

    </android.support.design.widget.AppBarLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

</android.support.design.widget.CoordinatorLayout>

当我说ViewPager的身高错误时,这就是我的意思 enter image description here

3 个答案:

答案 0 :(得分:4)

可能的黑客攻击可能是与工具栏相同的底部边距

?attr / actionBarSize 。你甚至可以摆弄其他可能的ui黑客利润来给你最好的结果。

答案 1 :(得分:2)

我花了很多时间在谷歌搜索并应用建议的答案,但我没有成功,所以决定深入研究问题并找到一个完整的答案,我想在这里分享。也许它会对某人有所帮助。

问题是当 ViewPager 折叠工具栏一起使用时,第一个没有正确计算其高度。如果您希望 ViewPager 将所有空间填充到屏幕底部,而不是更多 - 则存在问题。只需添加layout_marginBottom无法解决问题,因为折叠工具栏会在用户滚动时更改其高度。

因此,如果您希望 ViewPager 根据折叠工具栏高度变化调整其高度,则需要两件事:

  1. 自定义滚动行为。
  2. GlobalLayoutListener,它将在首次绘制时修复 ViewPager 高度。
  3. 这里是(用Kotlin编写的,但它只是一个单独的文件,可以直接放入Java项目中):

    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)
      }
    
    }
    

    并在您的代码中使用它们:

    1. 将自定义行为添加到 ViewPager app:layout_behavior="your.package.ViewPagerScrollingBehavior"

    2. 将自定义OnGlobalLayoutListener添加到 ViewPager viewPager.getViewTreeObserver().addOnGlobalLayoutListener(new FixHeightGlobalLayoutListener(this, mViewPager));

答案 2 :(得分:2)

基于Yevhenii的上述回答,我认为我设法以更简单的方式解决了这个问题:

class KeepWithinParentBoundsScrollingBehavior : AppBarLayout.ScrollingViewBehavior {

    constructor() : super()

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)


    override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
        if (dependency !is AppBarLayout) {
            return super.onDependentViewChanged(parent, child, dependency)
        }

        val layoutParams = child.layoutParams as CoordinatorLayout.LayoutParams
        layoutParams.height = parent.height - dependency.bottom
        child.layoutParams = layoutParams
        return super.onDependentViewChanged(parent, child, dependency)
    }
}

然后在app:layout_behavior="your.package.KeepWithinParentBoundsScrollingBehavior"ViewPager下的任何视图中设置AppBar

请注意,这并非适用于所有CoordinatorLayout的通用解决方案,但是当您在应用程序栏下面有一个视图时,您不想让其扩展到父级底部之外,这似乎可以解决问题CoordinatorLayout。