2014-12-30 27 views
7

Tôi có RecyclerView với 2 mục không lấp đầy toàn bộ màn hình. Làm cách nào để phát hiện người dùng đã nhấp vào phần trống của RecyclerView (có nghĩa là được nhấp trực tiếp trên RecyclerView chứ không phải một trong các mục của nó)?Phát hiện nhấp vào RecyclerView bên ngoài các mục

Trả lời

4

Bạn có thể phân lớp RecyclerView và ghi đè phương thức dispatchTouchEvent() để thực hiện việc này. Sử dụng phương pháp findChildViewUnder(), chúng tôi có thể xác định xem sự kiện chạm có xảy ra bên ngoài Chế độ xem con không và sử dụng interface để thông báo cho người nghe nếu có. Trong ví dụ sau, OnNoChildClickListenerinterface cung cấp chức năng đó.

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); 
    } 
} 

NB: Đây là điều chỉnh cho RecyclerView từ my answer here liên quan GridView.

+1

Cảm ơn bạn rất nhiều! Tôi đã kết thúc bằng cách sử dụng recyclerView.addOnItemTouchListener với findChildViewUnder (..). – Omar

+0

@Omar Ah! Rất tốt! Tôi vẫn còn làm quen với RecyclerView, và tôi vẫn chưa biết về giao diện đó. Cảm ơn bạn về thông tin! Bạn nên tạo câu trả lời cho điều đó. Bạn sẽ nhận được một upvote từ tôi. –

7

Như đã đề cập trong các bình luận

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) { 
    } 
}); 
+0

Cũng nên kiểm tra MotionEvent.getAction() == ACTION_UP, nếu không, bạn sẽ nhận được 2 sự kiện nhấp chuột. –

+0

Cảm ơn @ greg-ennis. Tôi đã cập nhật mã. –

+0

Đây phải là câu trả lời được chấp nhận. Nó cũng có thể là 'return false;' thay vì 'return;' bên dưới phần 'MotionEvent.ACTION_UP'. –

1

Bạn chỉ cần thiết lập một TouchListener trên RecyclerView như trình bày ở trên:

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; 
     } 
    }); 
2

@ câu trả lời Driss-Bounouar được gần như ngay mặc dù điều này sẽ ngăn chặn sự người dùng di chuyển chế độ xem của người tái chế như bất kỳ sự kiện nào khác sẽ khiến hành động của bạn xảy ra. Với một sửa đổi nhỏ, nơi chúng tôi ghi lại sự kiện xuống và sau đó kiểm tra sự kiện lên nếu tọa độ không thay đổi nhiều, sau đó kích hoạt sự kiện.

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; 
        } 
       }); 
Các vấn đề liên quan