RecyclerView嵌套RecyclerView,内层RecyclerView区域无法响应Item点击

问题描述

项目中遇到了一个RecyclerView内嵌套RecyclerView,内层RecyclerView的区域无法响应所在Item的点击事件的问题( RecyclerView内嵌套RecyclerView导致外层item点击不响应)。

首先,需要知道触摸事件的响应机制是怎么样的:由上至下,最下层不消费后,则由下至上;然后需要了解一下这三个方法:dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent。

dispatchTouchEvent:事件分发,一般不处理,返回false,事件到onInterceptTouchEvent中处理。

onInterceptTouchEvent:事件拦截,返回true的话,则不向下传递,事件到onTouchEvent,返回false事件往下传递

onTouchEvent:返回true代表事件消费,返回false不消费,事件往上传递。

只需要内部RecyclerView用于显示,不需要任何操作的情况下,为了使外层RecyclerView的item响应,把嵌入的RecyclerView触摸事件拦截,并且不消费就行了,事件就会传递到上一层,重写嵌套的RecyclerView

解决方式(形式不同,原理相同)

方式一

 

viewHolder.rv.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
               return viewHolder.itemView.onTouchEvent(event);
      }
 });

给内层的RecyclerView设置OnTouchListener,在onTouch中处理外层RecyclerView的Item的触摸事件onTouchEvent,item已经设置了点击事件,所以在onTouchEvent的事件处理中会调用到item的点击事件。

方式二

 

viewHolder.rv.setOnTouchListener(new View.OnTouchListener() {
     @Override
     public boolean onTouch(View v, MotionEvent event) {
          if(event.getAction() == MotionEvent.ACTION_UP){
              viewHolder.itemView.performClick();
          }
          return false;
     }
});

依然是给内层的RecyclerView设置OnTouchListener,在onTouch中调用外层RecyclerView的Item的preformClick方法,执行外层item的点击事件。

方式三(其实就是把方式二加了些判断封装了下)

 

viewHolder.rv.setOnTouchListener(new ChildTouchListener(viewHolder.itemView));

 

public class ChildTouchListener implements View.OnTouchListener{

    private float downX;
    private float downY;
    private float touchSlop;
    private View view;

    public ChildTouchListener(View view){
        this.view = view;
        touchSlop = ViewConfiguration.get(view.getContext()).getScaledTouchSlop();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getActionMasked()){
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_UP:
                if (Math.abs(event.getY() - downY) < touchSlop && Math.abs(event.getX() - downX) < touchSlop){
                    view.performClick();
                }
                break;
        }
        return false;
    }
}

依然是给内层的RecyclerView设置OnTouchListener,在onTouch中调用外层RecyclerView的Item的preformClick方法,执行外层item的点击事件,就是加了些判断。

总结

我们上面也说了,其实原理是相同的,里面的RecyclerView区域点击没响应,是因为RecyclerView内部重写了onTouchEvent方法,导致了上述问题的发生,然后我们给RecyclerView设置OnTouchListener,那么OnTouchListener中的onTouch方法会在onTouchEvent方法之前回调,并且需要注意onTouch方法的返回值,如果是false,onTouchEvent方法才会被调用,如果是true,那么onTouchEvent方法将不会被调用(也就是给view设置的OnTouchListener的优先级高于onTouchEvent),我们的处理中返回false以便不影响RecyclerView后续onTouchEvent中的固有逻辑。另外onTouchEvent方法中,如果当前View设置的有OnClickListener,那么它的onClick方法会被调用,这也就是方法1中直接调用了itemView的onTouchEvent方法,自然后续会调用到我们设置的OnClickListener中的onClick方法,执行我们想要的业务逻辑。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RecyclerView 嵌套 RecyclerView 可以用来实现一些复杂的列表布局,比如类似于网格布局的效果。实现的方法可以分为两种:使用 RecyclerView.Adapter 实现和使用 RecyclerView.LayoutManager 实现。 1. 使用 RecyclerView.Adapter 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 Adapter 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 Adapter 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerAdapter> innerAdapters; public void setInnerAdapters(List<InnerAdapter> innerAdapters) { this.innerAdapters = innerAdapters; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setAdapter(innerAdapters.get(position)); } @Override public int getItemCount() { return innerAdapters.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); innerRecyclerView.setLayoutManager(new LinearLayoutManager(itemView.getContext(), RecyclerView.HORIZONTAL, false)); } } } ``` 在内层 RecyclerView 的 Adapter 中,需要重写 onCreateViewHolder 方法,创建内层 RecyclerView 的 ViewHolder,同时需要重写 onBindViewHolder 方法,将数据绑定到内层 RecyclerView 的 ViewHolder 上。 ```java public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.InnerViewHolder> { private List<String> data; public void setData(List<String> data) { this.data = data; } @NonNull @Override public InnerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_inner, parent, false); return new InnerViewHolder(view); } @Override public void onBindViewHolder(@NonNull InnerViewHolder holder, int position) { holder.textView.setText(data.get(position)); } @Override public int getItemCount() { return data.size(); } static class InnerViewHolder extends RecyclerView.ViewHolder { TextView textView; public InnerViewHolder(@NonNull View itemView) { super(itemView); textView = itemView.findViewById(R.id.text_view); } } } ``` 2. 使用 RecyclerView.LayoutManager 实现 在外层 RecyclerView 的 Adapter 中,需要将内层 RecyclerView 的 LayoutManager 一并传递进去,同时需要重写 onBindViewHolder 方法,将内层 RecyclerView 的 LayoutManager 绑定到内层 RecyclerView 上。 ```java public class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.OuterViewHolder> { private List<InnerLayoutManager> innerLayoutManagers; public void setInnerLayoutManagers(List<InnerLayoutManager> innerLayoutManagers) { this.innerLayoutManagers = innerLayoutManagers; } @NonNull @Override public OuterViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_outer, parent, false); return new OuterViewHolder(view); } @Override public void onBindViewHolder(@NonNull OuterViewHolder holder, int position) { holder.innerRecyclerView.setLayoutManager(innerLayoutManagers.get(position)); } @Override public int getItemCount() { return innerLayoutManagers.size(); } static class OuterViewHolder extends RecyclerView.ViewHolder { RecyclerView innerRecyclerView; public OuterViewHolder(@NonNull View itemView) { super(itemView); innerRecyclerView = itemView.findViewById(R.id.inner_recycler_view); } } } ``` 在内层 RecyclerView 的 LayoutManager 中,需要重写 generateDefaultLayoutParams 方法,设置内层 RecyclerView 的布局参数,同时需要重写 canScrollHorizontally 和 canScrollVertically 方法,判断内层 RecyclerView 是否可以滑动。 ```java public class InnerLayoutManager extends LinearLayoutManager { public InnerLayoutManager(Context context) { super(context); } @Override public RecyclerView.LayoutParams generateDefaultLayoutParams() { return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); } @Override public boolean canScrollHorizontally() { return false; } @Override public boolean canScrollVertically() { return false; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值