2015-08-30 5 views
2

У меня есть родительский рециклинг с заполненными карточками и внутренним recyclerview внутри каждой карты.Внутренний Recyclerview не получает событие клика

Прокрутка для внутреннего recyclerview внутри карточек была отключена, но это также повлияло на способность внутреннего recyclerview получать события кликов.

Чтобы отключить скроллинг, я последовал за очень похоже подошли к ответу Лукаса Кроуфорд здесь, который предположил, что вы создаете пользовательский класс recyclerview и переопределить dispatchTouchEvent: Disable Scrolling in child Recyclerview android

Мой класс выглядит следующим образом:

public class ScrollThroughRecyclerView extends RecyclerView { 

    private boolean isOnClick; 

    public ScrollThroughRecyclerView(Context context) { 
     super(context); 
    } 

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

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

    @Override 
    public boolean dispatchTouchEvent(MotionEvent ev) { 
     final int action = ev.getAction(); 
     final int actionMasked = action & MotionEvent.ACTION_MASK; 
     Log.e("actionmasked", "" + actionMasked); 

     switch (actionMasked) { 
      case MotionEvent.ACTION_DOWN: 
       Log.e("motionDown", "onclick: "+isOnClick); 
       isOnClick = true; 
       break; 
      case MotionEvent.ACTION_MOVE: 
       isOnClick = false; 
       Log.e("motionMove", "onclick: "+isOnClick); 
       return true; 
      case MotionEvent.ACTION_UP: 
       Log.e("motionUp", "onclick: "+isOnClick); 
       if (isOnClick) { 
        return super.dispatchTouchEvent(ev); 
       } 
       break; 
      default: 
       return true; 
     } 
     return true; 
    } 

Однако он никогда не регистрирует события кликов, но прокрутка отключена правильно.

Как я могу получить внутренний recyclerview для регистрации событий кликов?

+0

Вы, возможно, идти лучше с 'ExpandableListView' –

ответ

4

Итак, примерно через день, пытаясь понять это, мне, наконец, удалось решить эту проблему.

После того, как вы сделали все эти шаги, вы должны закончить с:

  • Наружный recyclerview, который не препятствует СВИТОК событий внутренней recyclerview - скроллинг во внутреннем recyclerview отключена. Это полезно в сценарии, когда вы хотите использовать подход коллапсирующей панели инструментов с использованием внешнего и внутреннего recyclerview.
  • Элементы во внутреннем recyclerview можно щелкнуть (что используется внутренний recyclerview, отображающий список элементов, если они не могут быть нажаты).

Во-первых, я смотрел несколько видео на тему прикосновения в андроида: https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19

Я получил ссылку на видео отсюда: Android: Difference between onInterceptTouchEvent and dispatchTouchEvent?

Теперь я должен настроить свой onDispatchTouchEvent:

@Override 
public boolean dispatchTouchEvent(MotionEvent ev) { 
    final int action = ev.getAction(); 
    final int actionMasked = action & MotionEvent.ACTION_MASK; 
    Log.e("actionmasked", "" + actionMasked); 
    switch (actionMasked) { 
     case MotionEvent.ACTION_DOWN: 
      return super.dispatchTouchEvent(ev); 
     case MotionEvent.ACTION_MOVE: 
      return true; 
     case MotionEvent.ACTION_CANCEL: 
      return true; 
     case MotionEvent.ACTION_UP: 
      return super.dispatchTouchEvent(ev); 
     default: 
      return super.dispatchTouchEvent(ev); 
    } 

Я назвал super.dispatchTouchEvent (ev) как в DOWN, так и в UP и случаях по умолчанию, так как мы хотим, чтобы дочерний элемент внутреннего recyclerview обрабатывал эти события. Событие должно перейти из группы просмотра, которая представляет собой этот пользовательский recyclerview (ScrollThroughRecyclerView), к представлениям в recyclerview.

Для MOVE и CANCEL мы возвращаем true, чтобы сказать, что внутренний recyclerview обработал эти события, и событие может вернуться назад к родительскому элементу, что позволит внешнему recyclerview правильно прокручиваться. Это не будет препятствовать поведению приложения сворачивающейся панели инструментов.

Теперь нам нужен метод пользовательского onInterceptTouchEvent:

@Override 
public boolean onInterceptTouchEvent(MotionEvent e) { 
    final int action = e.getAction(); 
    final int actionMasked = action & MotionEvent.ACTION_MASK; 
    if (actionMasked == MotionEvent.ACTION_DOWN) { 
     return false; //intercepted by the viewgroup and passed down to child 
    } else if (actionMasked == MotionEvent.ACTION_UP) { 
     return false; //intercepted by the viewgroup and passed down to child 
    } 
    return super.onInterceptTouchEvent(e); 
} 

Для вверх и вниз, мы возвращаем фальшивы, как мы хотим, чтобы ребенок внутри внутренного recyclerview для обработки этих событий (с UP и DOWN, мы можем определить, какой элемент в recyclerview фактически нажал).

Для всего остального мы используем поведение по умолчанию, поэтому я вызывал: super.onInterceptTouchEvent (е)

Теперь адаптер recyclerview:

@Override 
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 
    if (holder instanceof PostViewHolder) { 
     ((PostViewHolder) holder).rl.setOnTouchListener(onTouchListener); 
    } 

Установите touchlistener на взгляд вы слушаете для сенсорного события в вашей recyclerview. Для меня, поскольку я слушаю клики по всей строке recyclerview, я устанавливаю сенсорный прослушиватель на rl, что означает относительную длину строки, отображаемой в recyclerview.

Сенсорный исполнитель не получит элементы ВНИЗ и ВВЕРХ, которые группа просмотра прошла через метод onInterceptTouchEvent.

Поскольку у нас есть только DOWN и UP motionevent, обнаружение кликов может быть немного утомительным, чем обычный способ сказать setOnClickListener. Кроме того, поскольку вы используете Touch, Touch фактически переопределяет onClickListener, и ничего не вызывается onClickListener. Для обнаружения щелчков по этому вопросу в recyclerview через onTouchListener, вы будете нуждаться в этом методе:

View.OnTouchListener onTouchListener = new View.OnTouchListener() { 
    private float startX; 
    private float startY; 
    private static final int CLICK_ACTION_THRESHHOLD = 5; 
    @Override 
    public boolean onTouch(View v, MotionEvent event) { 
     switch (event.getAction()) { 
      case MotionEvent.ACTION_DOWN: 
       startX = event.getX(); 
       startY = event.getY(); 
       break; 
      case MotionEvent.ACTION_UP: { 
       float endX = event.getX(); 
       float endY = event.getY(); 
       if (isAClick(startX, endX, startY, endY)) { 
        Log.e("UserClick", "user has clicked");// WE HAVE A CLICK!! 
       } 
       break; 
      } 
      default: 
       return true; 
     } 
     return true; 
    } 

    private boolean isAClick(float startX, float endX, float startY, float endY) { 
     float differenceX = Math.abs(startX - endX); 
     float differenceY = Math.abs(startY - endY); 
     if (differenceX > CLICK_ACTION_THRESHHOLD || differenceY > CLICK_ACTION_THRESHHOLD) { 
      return false; 
     } 
     return true; 
    } 
}; 
Смежные вопросы