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,包含一个AppbarLayout作为头部View,下面是一个ViewPager指示器,再下面是一个ViewPager。

最终效果:
最终效果

主页布局代码:

<?xml version="1.0" encoding="utf-8"?>
<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

  • 35
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
CoordinatorLayoutAndroid Design Support Library 提供的一个特殊的布局容器,它可以协调其内部的子 View 之间的交互行为,实现各种复杂的交互效果,比如 AppBarLayout 和 FloatingActionButton 的联动效果。 CoordinatorLayout 的主要作用是让子 View 之间可以通过 Behavior 进行交互。Behavior 是指子 View 在 CoordinatorLayout 的交互行为的定义,可以让子 View 之间实现联动效果,如 FloatingActionButton 随着 Snackbar 的出现和消失而改变位置,子 View 之间的交互行为通过 Behavior 实现。 使用 CoordinatorLayout 需要注意以下几点: 1. CoordinatorLayout 必须作为根布局。 2. 子 View 需要设置 app:layout_behavior 属性,指定其交互行为的 Behavior。 3. 子 View 的交互行为需要在 Behavior 定义。 下面是一个简单的 CoordinatorLayout 的示例: ``` <androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.google.android.material.appbar.CollapsingToolbarLayout android:layout_width="match_parent" android:layout_height="200dp" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:src="@drawable/image"/> <androidx.appcompat.widget.Toolbar android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin"/> </com.google.android.material.appbar.CollapsingToolbarLayout> </com.google.android.material.appbar.AppBarLayout> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </androidx.coordinatorlayout.widget.CoordinatorLayout> ``` 在上面的示例,AppBarLayout 和 CollapsingToolbarLayout 实现了一个可折叠的 Toolbar,RecyclerView 使用了 appbar_scrolling_view_behavior Behavior,实现了和可折叠的 Toolbar 的联动效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值