【问题标题】:Handle touch event for items inside Recyclerview - android处理 Recyclerview 中的项目的触摸事件 - android
【发布时间】:2015-07-05 00:00:54
【问题描述】:

我正在构建一个带有自定义布局(文本视图和开关)和自定义适配器的简单回收视图。

我的问题是我无法处理开关的点击事件(这使它切换其状态),我为RecyclerView 构建了一个触摸侦听器,每次点击Switch 时它都会触发。

经过大量试验后,开关触摸侦听器也会触发,但如果单击开关,我想禁用 recyclerView 的触摸事件。

这是我的布局代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="60.0dip"
android:layout_weight="1.0"
android:orientation="horizontal"
android:paddingLeft="16dp">

<TextView
    android:id="@+id/category_name"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="false"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:text="Category Name"
    android:textAppearance="?android:textAppearanceLarge" />

<android.support.v7.widget.SwitchCompat
    android:id="@+id/category_switch"
    android:layout_width="80dp"
    android:layout_height="wrap_content"
    android:layout_alignParentEnd="true"
    android:layout_alignParentRight="true"
    android:layout_centerVertical="true"
    android:layout_gravity="center_vertical"
    android:checked="true"
    android:clickable="true"
    android:focusable="false"
    android:focusableInTouchMode="false"
    android:paddingRight="16dp" />

</RelativeLayout>

这是我的适配器代码:

public CategoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

    View row = layoutInflater.inflate(R.layout.single_row_category, parent, false);
    CategoryViewHolder holder = new CategoryViewHolder(row);

    return holder;
}

public void onBindViewHolder(CategoryViewHolder holder, final int position) {
    AlarmCategory thisCat = categories.get(position);

    holder.catName.setText(thisCat.getCategoryName());

    holder.catStatus.setChecked(thisCat.isOn());

    holder.catStatus.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            Log.d("fpp", view.getClass().getName() + " is clicked");
            return true;
        }
    });
}

public class CategoryViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener {

    public TextView catName;
    public SwitchCompat catStatus;

    public CategoryViewHolder(View itemView) {
        super(itemView);
        itemView.setOnCreateContextMenuListener(this);

        catName = (TextView) itemView.findViewById(R.id.category_name);
        catStatus = (SwitchCompat) itemView.findViewById(R.id.category_switch);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo contextMenuInfo) {
        menu.add(0, 1001, 0, "Edit");//groupId, itemId, order, title
        menu.add(0, 1002, 1, "Delete");
    }
}

这是我的 recyclerView 触摸处理程序:

class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {

    private GestureDetector gestureDetector;
    private ClickListener clickListener;

    public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {

        this.clickListener = clickListener;

        gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                if (child != null && clickListener != null) {
                    clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
        if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
            clickListener.onClick(child, rv.getChildPosition(child));

            Log.d("fpp", child.getClass().getName() + " is clicked");

            return false;
        }

        return false;
    }

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

    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }
}

onCreate 方法中我通过以下方式调用它:

recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView, new ClickListener() {
        @Override
        public void onClick(View view, int position) {
            Intent i = new Intent(CategoriesList.this, AlarmList.class);
            i.putExtra("catID", categories.get(position).getCategoryID());
            startActivity(i);
        }

        @Override
        public void onLongClick(View view, int position) {
            catPos = position;
        }
    }));

请帮忙,我已经尝试了很多解决方案,但没有任何效果,抱歉。

提前致谢。

【问题讨论】:

    标签: android android-recyclerview touch-event android-switch


    【解决方案1】:

    一种方法是更新您的持有者以在内部处理任何视图点击,例如

    public class CategoryViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener, CompoundButton.OnSetCheckedListener {
        public CategoryViewHolder(View itemView) {
            super(itemView);
            itemView.setOnCreateContextMenuListener(this);
            itemView.setOnClickListener(this);
    
            catName = (TextView) itemView.findViewById(R.id.category_name);
            catStatus = (SwitchCompat) itemView.findViewById(R.id.category_switch);
            catStatus.setOnCheckChangedListener(this);
        }
    
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            // deal with catStatus change
        }
    
        public void onClick(View view) {
            // deal with itemView click
        }
    }
    

    【讨论】:

    • 感谢您的回答,但我写了这段代码并添加了Log.d("fopp", view.getClass().getName() + " is clicked from inner");,但抱歉没有发生任何事情
    • 您正在使用一个手势检测器,它会窃取触摸事件并且它不会被传播到其他任何东西。答案中的代码有效,但为此您需要删除 1) recyclerView.addOnItemTouchListener() 部分和 2) 手势检测器
    • 以及如何处理布局本身的触摸事件?当点击开关以外的任何东西时,我想导航到另一个活动。
    • onClick(View view) 是用于点击布局的那个,即itemViewitemView 是您的膨胀布局视图演示。只需将您的活动导航代码移动到该方法中即可。
    【解决方案2】:
    1. 创建类RecyclerTouchListener

      public class RecyclerTouchListener implements RecyclerView.OnItemTouchListener {
      private GestureDetector gestureDetector;
      private ClickListener clickListener;
      
      public RecyclerTouchListener(Context context, final RecyclerView recyclerView, final ClickListener clickListener) {
          this.clickListener = clickListener;
          gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
              @Override
              public boolean onSingleTapUp(MotionEvent e) {
                  return true;
              }
      
              @Override
              public void onLongPress(MotionEvent e) {
                  View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
                  if (child != null && clickListener != null) {
                      clickListener.onLongClick(child, recyclerView.getChildPosition(child));
                  }
              }
          });
      }
      
      @Override
      public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
          View child = rv.findChildViewUnder(e.getX(), e.getY());
          if (child != null && clickListener != null && gestureDetector.onTouchEvent(e)) {
              clickListener.onClick(child, rv.getChildPosition(child));
          }
          return false;
      }
      
      @Override
      public void onTouchEvent(RecyclerView rv, MotionEvent e) {
      
      }
      
      @Override
      public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
      
      }
      
      public interface ClickListener {
          void onClick(View view, int position);
      
          void onLongClick(View view, int position);
        }
      }
      
    2. 在活动中使用这个监听器

      recyclerview.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerview, new RecyclerTouchListener.ClickListener() {
              @Override
              public void onClick(View view, int position) {
      
                 // Write your code here
      
              }
      
              @Override
              public void onLongClick(View view, int position) {
      
              }
          }));
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-12-02
      • 2016-05-28
      • 2011-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-09
      相关资源
      最近更新 更多