您的位置:首页 > 产品设计 > UI/UE

CoordinatorLayout使用中的坑

2016-12-12 18:38 459 查看
前言:因为项目中有个界面使用到父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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息