检测项目外部的RecyclerView

时间:2014-12-30 10:31:25

标签: android android-recyclerview

我有一个带有2个项目的RecyclerView,它们不会填满整个屏幕。如何检测到用户点击了RecyclerView的空白部分(意味着直接点击了RecyclerView而不是其中一个项目)?

7 个答案:

答案 0 :(得分:14)

如评论中所述

mRecyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {

  @Override
  public boolean onInterceptTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
    if (motionEvent.getAction() != MotionEvent.ACTION_UP) {
        return false;
    }
    View child = recyclerView.findChildViewUnder(motionEvent.getX(), motionEvent.getY());
    if (child != null) {
      // tapped on child
      return false;
    } else {
      // Tap occured outside all child-views.
      // do something
      return true;
    }
  }

  @Override
  public void onTouchEvent(RecyclerView recyclerView, MotionEvent motionEvent) {
  }
});

答案 1 :(得分:11)

您可以继承RecyclerView并覆盖dispatchTouchEvent()方法来完成此操作。使用findChildViewUnder()方法,我们可以确定触摸事件是否发生在子视图之外,并使用interface通知侦听器是否存在。在以下示例中,OnNoChildClickListener interface提供了该功能。

public class TouchyRecyclerView extends RecyclerView
{
    // Depending on how you're creating this View,
    // you might need to specify additional constructors.
    public TouchyRecyclerView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    private OnNoChildClickListener listener;
    public interface OnNoChildClickListener
    {
        public void onNoChildClick();
    }

    public void setOnNoChildClickListener(OnNoChildClickListener listener)
    {
        this.listener = listener;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event)
    {
        // The findChildViewUnder() method returns null if the touch event
        // occurs outside of a child View.
        // Change the MotionEvent action as needed. Here we use ACTION_DOWN
        // as a simple, naive indication of a click.
        if (event.getAction() == MotionEvent.ACTION_DOWN
            && findChildViewUnder(event.getX(), event.getY()) == null)
        {
            if (listener != null)
            {
                listener.onNoChildClick();
            }
        }
        return super.dispatchTouchEvent(event);
    }
}

注意:这适用于RecyclerView GridView关于{{1}}。{/ p>

答案 2 :(得分:4)

@ driss-bounouar的回答几乎是正确的,但这会阻止用户滚动回收者视图,因为任何向下事件都会导致您的操作发生。稍微修改我们记录向下事件,然后检查up事件,如果坐标没有太大变化,则触发事件。

private MotionEvent lastRecyclerViewDownTouchEvent;
myRecyclerView.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        if (event.getAction() == MotionEvent.ACTION_DOWN && myRecyclerView.findChildViewUnder(event.getX(), event.getY()) == null) {
                            lastRecyclerViewDownTouchEvent = event;
                        } else if (event.getAction() == MotionEvent.ACTION_UP && myRecyclerView.findChildViewUnder(event.getX(), event.getY()) == null
                                && lastRecyclerViewDownTouchEvent != null) {
                            // Check to see if it was a tap or a swipe
                            float xDelta = Math.abs(lastRecyclerViewDownTouchEvent.getX() - event.getX());
                            float yDelta = Math.abs(lastRecyclerViewDownTouchEvent.getY() - event.getY());
                            if (xDelta < 30 && yDelta < 30) {
                                // Do action
                            }
                            lastRecyclerViewDownTouchEvent = null;
                        }
                        return false;
                    }
                });

答案 3 :(得分:1)

您只需在上面显示的TouchListener上设置RecyclerView

categoryTable.setAdapter(new CatgoriesAdapter(categories.getWrappedList()));
    categoryTable.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_DOWN
                    && categoryTable.findChildViewUnder(event.getX(), event.getY()) == null)
            {
                // Touch outside items here, you do whatever you want  
                HideCategoryMenu();
            }
            return false;
        }
    });

答案 4 :(得分:1)

这对我有用,我用它来代替 RecyclerView:

public class ClickeableRecyclerView extends RecyclerView
{
    private static final int CLICK_DURATION = 800;
    private CountDownTimer clickCountDown;
    private final Object sincClick = new Object();
    private boolean shortClick = true;

    public ClickeableRecyclerView(@NonNull Context context)
    {
        super(context);
        init();
    }

    public ClickeableRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs);
        init();
    }

    public ClickeableRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init()
    {
        clickCountDown = new CountDownTimer(CLICK_DURATION, 100)
        {
            public void onTick(long millisUntilFinished)
            {
                synchronized(sincClick)
                {
                    shortClick = true;
                }
            }
            public void onFinish()
            {
                synchronized(sincClick)
                {
                    shortClick = false;
                }
            }
        };
    }

    @Override
    public boolean onTouchEvent(MotionEvent e)
    {
        if(findChildViewUnder(e.getX(), e.getY()) == null)
        {
            if(e.getAction() == MotionEvent.ACTION_DOWN)
            {
                clickCountDown.start();
            }
            else if(e.getAction() == MotionEvent.ACTION_UP)
            {
                synchronized(sincClick)
                {
                    if(shortClick)
                    {
                        performClick();
                        clickCountDown.cancel();
                    }
                }
            }
        }
        else
        {
            clickCountDown.cancel();
        }
        return super.onTouchEvent(e);
    }

    @Override
    public boolean performClick()
    {
        return super.performClick();
    }
}

在布局中:

<yourpackage.ClickeableRecyclerView
    android:id="@+id/recyclerViewItems"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:background="@color/white"
    android:visibility="visible"
    app:layout_constraintBottom_toTopOf="@+id/viewTotal"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/buttonShowItems"
    tools:visibility="visible" />

在活动中:

private ClickeableRecyclerView recyclerView;

recyclerView = findViewById(R.id.recyclerView);

recyclerView.setOnClickListener(new View.OnClickListener()
{
    @Override
    public void onClick(View v)
    {
        // Do something when click no items
    }
});

希望能帮到你。

答案 5 :(得分:0)

shortcutDeviceRecly.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {

                if(event.getAction() == MotionEvent.ACTION_UP){
                    roomClickEvent(true, v);
                }

                return false;
            }
        });

答案 6 :(得分:0)

@Angel Kjoseski的答案在科特林看起来像这样:

yourRecyclerView.addOnItemTouchListener(object : RecyclerView.OnItemTouchListener {
                override fun onInterceptTouchEvent(recyclerView: RecyclerView, motionEvent: MotionEvent): Boolean {
                    return when {
                        motionEvent.action != MotionEvent.ACTION_UP || recyclerView.findChildViewUnder(motionEvent.x, motionEvent.y) != null -> false
                        else -> {
                            // do something here
                            true
                        }
                    }
                }

                override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}
                override fun onTouchEvent(recyclerView: RecyclerView, motionEvent: MotionEvent) {}
            })