Problem

问题

I am attempting to simulate the exact behaviour of the Google Play application.

我正在尝试模拟谷歌Play应用程序的确切行为。

Currently when you're scrolling through a category like 'Top Games' and you touch the list, that cell as well as the RecyclerView handles the touch event, you can tell they are both handling it due to the ripple appearing when you hold your finger down as well as the scrolling coming to a stop. Or if you click on a cell whilst the list is still moving that content is opened straight away.

现在当你翻阅一个类别的顶级游戏和你接触到列表,该细胞以及RecyclerView处理触摸事件,你可以告诉他们都是处理由于波纹出现,当你按下手指以及滚动停止。或者,如果您在列表仍在移动的时候单击单元格,那么内容将立即打开。

The default behaviour is for the scrolling to instantly stop if you place your finger down whilst it's moving, and for it then to consume that touch event, meaning the cell never gets told about that touch. This is incredibly irritating when your applications main content is in a RecyclerView and if the user is continuously scrolling then clicking on a cell, it requires them to click twice, as the first click has been consumed by stopping the scroll, even if the list was barely moving.

默认的行为是,当你的手指在移动时向下滚动,它会立即停止,然后它会消耗那个触摸事件,这意味着单元格永远不会被告知那个触摸。当你的应用程序的主要内容在一个回收视图中,如果用户不断滚动然后点击一个单元格,它需要他们点击两次,因为第一次点击已经被停止滚动所消耗,即使列表几乎没有移动。

What I've Tried So Far

我已经试过了

At first I thought there must be some kind of flag inside the RecyclerView which tells it not to consume the touch event. I've looked through the Android source code and routed through the Android documentation to no avail.

一开始我认为回收视图中一定有某种标志告诉它不要使用触摸事件。我查看了Android的源代码,并在Android文档中查找,但没有发现任何问题。

Then I tried to capture the touch event with onInterceptTouchEvent and manually tell my view that it's being touched;

然后我尝试用onInterceptTouchEvent捕获触摸事件并手动告诉我的视图它正在被触摸;

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    View myCell = recyclerView.findChildViewUnder(event.getX(), event.getY());
    myCell.dispatchTouchEvent(event);
    return super.onInterceptTouchEvent(event);
}

Here, dispatchTouchEvent didn't seem to do anything even though the view I was getting had the corresponding tag which I set in the adapter.

这里,dispatchTouchEvent似乎没有做任何事情,即使我得到的视图有对应的标签,我在适配器中设置了。

I've tried shooting this problem with my code machine gun at all angles; playing with requestDisallowInterceptTouchEvent, manually calling onTouch and overriding all manner of listeners for the RecyclerView and beyond.

我试过用我的代码机枪从各个角度解决这个问题;使用requestDisallowInterceptTouchEvent,手动调用onTouch,并覆盖所有类型的侦听器,用于回收类视图等。

Nothing seems to be working. I'm sure there must be an elegant solution to this and I've skimmed over an important detail somewhere along the path to insanity? Especially because Google's own apps behave in this manner.

似乎什么也没有起作用。我确信一定有一个优雅的解决方案,我在精神错乱的道路上略去了一个重要的细节?尤其是谷歌自己的应用程序是这样运行的。

Please help! :) Thanks.

请帮助!:)谢谢。

The Solution

解决方案

Thanks to Jagoan Neon a solution has been found. I ended up wrapping his answer inside a custom RecyclerView for ease of use.

多亏了Jagoan霓虹灯,我们找到了解决方案。最后我将他的答案封装在一个自定义的回收视图中,以便于使用。

public class MultiClickRecyclerView extends RecyclerView {
   public MultiClickRecyclerView(Context context) {
        super(context);
   }

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

   public MultiClickRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
   }

   @Override
   public boolean onInterceptTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN && this.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) {
            this.stopScroll();
        }
        return super.onInterceptTouchEvent(event);
   }
}

1 个解决方案

#1


9

First off you should define an OnItemTouchListener, perhaps as a global variable like this:

首先,您应该定义一个OnItemTouchListener,可能作为这样的全局变量:

RecyclerView.OnItemTouchListener mOnItemTouchListener = new RecyclerView.OnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        if (e.getAction() == MotionEvent.ACTION_DOWN && rv.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING) {
            Log.d(TAG, "onInterceptTouchEvent: click performed");
            rv.findChildViewUnder(e.getX(), e.getY()).performClick();
            return true;
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {}

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
};

Why ACTION_DOWN and SCROLL_STATE_SETTLING?

为什么ACTION_DOWN和SCROLL_STATE_SETTLING呢?

ACTION_DOWN motion event will be triggered when you perform a touch on the RecyclerView, and at that exact point in time RecyclerView changes its scrolling state to SCROLL_STATE_SETTLING as it tries to stop the scrolling. And that's exactly when you want to perform the click.

ACTION_DOWN动作事件将在您对回收视图执行触摸时触发,并且在回收视图试图停止滚动时将其滚动状态更改为scroll_state_settlement。这正是你想要执行点击的时候。

And remember to return true so that you're telling your RecyclerView that you've consumed the MotionEvent. Otherwise your performClick() might be called more than once.

记住返回true,这样你就告诉你的回收视图你已经消耗了MotionEvent。否则,可能会多次调用performClick()。

Add it to your RecyclerView at onResume and remove it at onPause, and you're all set ;)

将它添加到onResume的回收视图中,并在onPause中删除,您就完成了;

UPDATE

更新

Add a null checker when you're doing findChildViewUnder - it returns null when you're not touching a specific cell.

在做findChildViewUnder时添加一个空检查器——当您没有接触到特定的单元格时,它将返回null。

View childView = rv.findChildViewUnder(e.getX(), e.getY());
if (childView != null) childView.performClick();

UPDATE 2

更新2

Turns out that stopping the RecyclerView from scrolling would suffice. Do this instead:

事实证明,停止滚动回收视图就足够了。这样做:

@Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        if (e.getAction() == MotionEvent.ACTION_DOWN && rv.getScrollState() == RecyclerView.SCROLL_STATE_SETTLING)
            rv.stopScroll();
        return false;
    }

更多相关文章

  1. 在android上滚动时,列表视图的位置会发生变化
  2. android里通过什么什么事件可以拿到由于click后的EditText的光标
  3. 如何在android中的recycler视图中显示第一项的选择?
  4. java中的事件监听问题,如何将菜单项与组合框相关联
  5. springMVC使用html视图配置详解
  6. java中的大事件
  7. Javascript 事件对象(六)事件默认行为
  8. javascript(六)js事件绑定浏览器兼容解决方案 attachEvent addEve
  9. 在JComboBox箭头JButton上附加动作事件

随机推荐

  1. Android(安卓)椭圆轨迹动画
  2. 丢失android系统库或Conversion to Dalvi
  3. 用Xamarin 实现园友的 :Android浮动小球与
  4. Android 开机log以及常见异常
  5. Android(安卓)Eventbus控件发送与接收
  6. android中解析文件的三种方式
  7. Android数据库升级
  8. Android下uid与多用户释疑(一)
  9. Android(安卓)源码解析 - ScrollView
  10. android的init实例