CoordinatorLayout使用中的坑

前言:因为项目中有个界面使用到父view和子view嵌套滑动的效果,所以想使用CoordinatorLayout来实现。在这当中遇到一些坑,本文作为一个记录。

现在用的UI库版本:
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.android.support:support-v4:24.2.1'
compile 'com.android.support:design:24.2.1'

ps:因为我现在遇到的坑可能在之后的版本会修复,所以就先版本写这。

页面大体结构:
CoordinatorLayout使用中的坑_第1张图片

刚开始的实现想法是,整个结构是CoordinatorLayout,包含一个AppbarLayout作为头部View,下面是一个ViewPager指示器,再下面是一个ViewPager。

最终效果:

主页布局代码:


<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.oacg.collapsingtoolbarlayoutdemo.CoorAndViewPagerActivity">
    <android.support.design.widget.AppBarLayout
        android:id="@+id/profile_app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
        android:fitsSystemWindows="true">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/profile_collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="280dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed"
            app:contentScrim="?attr/colorPrimary"
            android:fitsSystemWindows="true">

            <ImageView
                android:id="@+id/image"
                android:layout_width="match_parent"
                android:layout_height="280dp"
                android:scaleType="centerCrop"
                android:fitsSystemWindows="true"
                android:src="@drawable/bg"
                android:maxHeight="192dp"
                app:layout_collapseMode="parallax"/>

        android.support.design.widget.CollapsingToolbarLayout>

        <com.oacg.collapsingtoolbarlayoutdemo.SimpleViewPagerIndicator
            android:id="@+id/indicator"
            android:layout_width="match_parent"
            android:layout_height="50dp"/>

    android.support.design.widget.AppBarLayout>

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

android.support.design.widget.CoordinatorLayout>

出现的问题:
在滚动的时候出现一种卡顿的现象。主要是在NestedScrollView向上滚动和RecyclerView向下滚动的时候。AppbarLayout的滚动非常的不流畅。感觉上是没有了惯性滑动。

解决办法:

1.

这里可以看到 为了头部View滚动优先于ViewPager,所以我在给CollapsingToolbarLayout设置app:layout_scrollFlags的时候我使用的是:scroll|exitUntilCollapsed。加入ViewPager中的NestedScrollView和RecyclerView比较短的时候,可以考虑使用 scroll|exitUntilCollapsed|enterAlways

  • 会出现的问题:
    1.加入”enterAlways”这个flags后ViewPager会和头部View一起滚动。这样会造成:向下滚动的时候,你的头部View早就已经完全展开了,但是你的RecyclerView还没有滚动到顶部。或者向上滚动的时候,你的头部View还没有完全的折叠,你的RecyclerView已经向上滚动隐藏了一部分了。
    2.加上这个之后NestedScrollView的滚动更加卡顿了,不管是向上还是向下。当然可以使用RecyclerView来代替NestedScrollView。但是会增加部分代码,并且不直观。

2.

上面的解决方式显然是有很大的局限性。那么第二种解决方式。
即:
http://stackoverflow.com/questions/30923889/flinging-with-recyclerview-appbarlayout 第一个答案。用于解决RecyclerView的问题。
出现这种问题的原因大体上是因为RecyclerView在分发fling的时候出现了错误,导致AppbarLayout并没有获得fling的指令。所以这个方法,就自己重新计算了时候需要fling的判断。
但是这个方法还是没法解决NestedScrollView的滑动卡顿问题。虽然上面链接的第二个答案,看上去能解决NestedScrollView的滑动卡顿问题,但是并没有卵用。这个之后再说。

  • 会出现的问题:这种方式上基本可满足大体的情况。但是还有个问题就是当一个快速滚动遇到,AppbarLayout显示或者隐藏的交界的时候会停止。也就说一个fling事件只能在ViewPager或者AppbarLayout其中一个View中起作用,不能够在他们之间传递。所以会出现但我们再怎么用力滑动ViewPager中的控件,滑动的惯性都不会把AppbarLayout带着滚动起来。但是在腾讯漫画的目录页就实现了这个效果,至于腾讯漫画怎么实现的下次再说。
    效果图:

3.

上面的解决办法,大多是对于RecyclerView的对于NestedScrollView是无效的。因为在NestedScrollView根本就没有把fling正确的发出来。NestedScrollView的onTouchEvent()方法中:

            case MotionEvent.ACTION_UP:

                if (mIsBeingDragged) {
                    final VelocityTracker velocityTracker = mVelocityTracker;

                    velocityTracker.addMovement(vtev);

                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                    int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker,
                            mActivePointerId);
                    if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                        flingWithNestedDispatch(-initialVelocity);
                    } else if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
                            getScrollRange())) {
                        ViewCompat.postInvalidateOnAnimation(this);
                    }
                }
                mActivePointerId = INVALID_POINTER;
                endDrag();
                break;

触发up事件的时候会来处理fling事件。flingWithNestedDispatch(-initialVelocity) 用来发送fling事件和处理fling事件。出现卡顿的时候就是if (mIsBeingDragged) 这个判断为false的时候。
那么解决NestedScrollView滚动卡顿的办法就是:自己新建一个类,然后将NestedScrollView中的代码copy到新的类中,并在onTouchEvent()方法的case MotionEvent.ACTION_UP: 中去掉if (mIsBeingDragged) 判断,然后就可以流畅的滑动了。至于这个判断去掉会不会有什么其他问题,暂时我还没发现,如果您知道请务必告诉我。谢谢。

总结:CoordinatorLayout上的这个卡顿的问题,官方早就知道这个问题,官方说是v23就修复的,
现在v24了也没有变化。可以看这里的讨论。https://code.google.com/p/android/issues/detail?id=179501
As I said in the talk, no there is ETA and may not even land. Closing comments until we do. 看到这句话一口老血吐出来。这里写图片描述

所以在stackoverflow.com有很多的讨论,而且也有很多的解决办法,我感觉能达到的效果的都是有限的。不能真正的解决问题。

ps:https://github.com/henrytao-me/smooth-app-bar-layout 这个库是实现类似效果的,具体的效果怎么我没有去试。
pps: coordinatorlayout在android6.0的华为的机子上测试的时候快速滑动RecyclerView,会出现跳动的问题,暂时还不知道是因为我设置的问题还是因为coordinatorlayout的bug。

源码地址:https://github.com/BigggFish/CoordinatorlayoutDemo

参考:
http://dk-exp.com/2016/03/30/CoordinatorLayout/
http://stackoverflow.com/questions/30923889/flinging-with-recyclerview-appbarlayout
http://stackoverflow.com/questions/38119661/smooth-scroll-and-fling-with-nestedscrollview-appbarlayout-and-coordinatorlayout?rq=1

你可能感兴趣的:(android开发报错,安卓开发UI)