NestedScrollView 和 Horizo​​ntal RecyclerView 平滑滚动 [英] NestedScrollView and Horizontal RecyclerView Smooth Scrolling

查看:39
本文介绍了NestedScrollView 和 Horizo​​ntal RecyclerView 平滑滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个垂直的nestedscrollview,其中包含一堆带有水平布局管理器设置的recyclerview.这个想法与新的 google play 商店的外观非常相似.我能够让它发挥作用,但它根本不流畅.以下是问题:

1) 水平 recyclerview 项目在大多数情况下无法拦截触摸事件,即使我点击它.滚动视图似乎优先于大多数动作.我很难抓住水平运动.这种 UX 令人沮丧,因为我需要尝试几次才能奏效.如果您检查 Play 商店,它能够很好地拦截触摸事件,并且效果很好.我注意到在 Play 商店中,他们设置的方式是在一个垂直回收站视图中放置许多水平回收站视图.没有滚动视图.

2) 水平 recyclerviews 的高度必须手动设置,并且没有简单的方法来计算子元素的高度.

这是我使用的布局:

解决方案

所以平滑滚动的问题现在已经修复.这是由设计支持库(当前为 23.1.1)中的 NestedScrollView 中的错误引起的.

您可以在此处阅读有关该问题和简单修复的信息:https://code.google.com/p/android/issues/detail?id=194398

简而言之,在你执行了一个投掷之后,nestedscrollview 没有在滚动组件上注册一个完整的,所以它需要一个额外的 'ACTION_DOWN' 事件来释放父nestedscrollview 拦截(吃掉)后续事件.所以发生的事情是,如果您尝试滚动子列表(或 viewpager),在一次滑动之后,第一次触摸释放父 NSV 绑定,随后的触摸将起作用.这让用户体验变得非常糟糕.

本质上需要在 NSV 的 ACTION_DOWN 事件上添加这一行:

computeScroll();

这是我正在使用的:

public class MyNestedScrollView extends NestedScrollView {私人国际垃圾;私人浮动 mInitialMotionX;私人浮动 mInitialMotionY;公共 MyNestedScrollView(上下文上下文){超级(上下文);初始化(上下文);}私有无效初始化(上下文上下文){ViewConfiguration config = ViewConfiguration.get(context);slop = config.getScaledEdgeSlop();}公共 MyNestedScrollView(上下文上下文,AttributeSet attrs){超级(上下文,属性);初始化(上下文);}公共 MyNestedScrollView(上下文上下文,AttributeSet attrs,int defStyleAttr){超级(上下文,属性,defStyleAttr);初始化(上下文);}私人浮动 xDistance, yDistance, lastX, lastY;@覆盖公共布尔 onInterceptTouchEvent(MotionEvent ev) {最终浮点数 x = ev.getX();最终浮点 y = ev.getY();开关(ev.getAction()){案例 MotionEvent.ACTION_DOWN:xDistance = yDistance = 0f;lastX = ev.getX();lastY = ev.getY();//这是修复的非常重要的行计算滚动();休息;案例 MotionEvent.ACTION_MOVE:最终浮动 curX = ev.getX();最终浮动 curY = ev.getY();xDistance += Math.abs(curX - lastX);yDistance += Math.abs(curY - lastY);lastX = curX;lastY = curY;如果 (xDistance > yDistance) {返回假;}}返回 super.onInterceptTouchEvent(ev);}

}

在xml文件中使用这个类代替你的nestedscrollview,子列表应该正确拦截和处理触摸事件.

呼,实际上有很多像这样的错误让我想完全放弃设计支持库,并在它更成熟时重新访问它.

I have a single vertical nestedscrollview that contains a bunch of recyclerview with a horizontal layoutmanager setup. The idea is pretty similar to how the new google play store looks. I'm able to make it functional but it isn't smooth at all. Here are the problems:

1) The horizontal recyclerview item fails to intercept the touch event most of the times even though i tap right on it. The scroll view seems to take precedence for most of the motions. It's hard for me to get a hook onto the horizontal motion. This UX is frustrating as I need to try a few times before it works. If you check the play store, it is able to intercept the touch event really well and it just works well. I noticed in the play store the way they set it up is many horizontal recyclerviews inside one vertical recyclerview. No scrollview.

2) The height of the horizontal recyclerviews have to be manually set and there is no easy way to calculate the height of the children elements.

Here is the layout I'm using:

<android.support.v4.widget.NestedScrollView
    android:id="@+id/scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:clipToPadding="false"
    android:background="@color/dark_bgd"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <LinearLayout
            android:id="@+id/main_content_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone"
            tools:visibility="gone"
            android:orientation="vertical">                

                <android.support.v7.widget.RecyclerView
                    android:id="@+id/starring_list"
                    android:paddingLeft="@dimen/spacing_major"
                    android:paddingRight="@dimen/spacing_major"
                    android:layout_width="match_parent"
                    android:layout_height="180dp" />

This UI pattern is very basic and most likely used in many different apps. I've read many SO's where ppl say it's a bad idea to put a list within a list, but it is a very common and modern UI pattern used all over the place.Think of netflix like interface with a series of horizontal scroll lists inside a vertical list. Isn't there a smooth way to accomplish this?

Example image from the store:

解决方案

So the smooth scrolling issue is fixed now. It was caused by a bug in the NestedScrollView in the Design Support Library (currently 23.1.1).

You can read about the issue and the simple fix here: https://code.google.com/p/android/issues/detail?id=194398

In short, after you performed a fling, the nestedscrollview didn't register a complete on the scroller component and so it needed an additional 'ACTION_DOWN' event to release the parent nestedscrollview from intercepting(eating up) the subsequent events. So what happened was if you tried scrolling your child list(or viewpager), after a fling, the first touch releases the parent NSV bind and the subsequent touches would work. That was making the UX really bad.

Essentially need to add this line on the ACTION_DOWN event of the NSV:

computeScroll();

Here is what I'm using:

public class MyNestedScrollView extends NestedScrollView {
private int slop;
private float mInitialMotionX;
private float mInitialMotionY;

public MyNestedScrollView(Context context) {
    super(context);
    init(context);
}

private void init(Context context) {
    ViewConfiguration config = ViewConfiguration.get(context);
    slop = config.getScaledEdgeSlop();
}

public MyNestedScrollView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
}

public MyNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context);
}


private float xDistance, yDistance, lastX, lastY;

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    final float x = ev.getX();
    final float y = ev.getY();
    switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            xDistance = yDistance = 0f;
            lastX = ev.getX();
            lastY = ev.getY();

            // This is very important line that fixes 
           computeScroll();


            break;
        case MotionEvent.ACTION_MOVE:
            final float curX = ev.getX();
            final float curY = ev.getY();
            xDistance += Math.abs(curX - lastX);
            yDistance += Math.abs(curY - lastY);
            lastX = curX;
            lastY = curY;

            if (xDistance > yDistance) {
                return false;
            }
    }


    return super.onInterceptTouchEvent(ev);
}

}

Use this class in place of your nestedscrollview in the xml file, and the child lists should intercept and handle the touch events properly.

Phew, there are actually quite a few bugs like these that makes me want to ditch the design support library altogether and revisit it when its more mature.

这篇关于NestedScrollView 和 Horizo​​ntal RecyclerView 平滑滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆