返回

直击痛点!揭秘 RecyclerView 表项子控件点击监听的终极方案

Android

对于 Android 开发者来说,处理 RecyclerView 的表项点击事件可谓家常便饭。然而,当您需要监听表项中的特定子控件时,事情就会变得复杂。为了解决这一痛点,我们将深入探讨一种将 RecyclerView 表项点击监听器与 Adapter 分离的革命性方法,并揭示一种巧妙的技术,让您轻松监听 RecyclerView 表项子控件的点击事件。

RecyclerView 表项点击监听器的传统方式

传统上,RecyclerView 表项的点击事件处理是通过 RecyclerView.Adapter.onBindViewHolder() 方法实现的。这是一种简单但有限的方法,因为它无法区分表项中的不同子控件。

解耦 RecyclerView 适配器和点击监听器

为了解决这个问题,一种新的方法应运而生,它将点击监听器与 RecyclerView 适配器解耦。此方法涉及创建自定义的 ItemClickListener 接口和一个 ItemClickSupport 类来管理点击事件。

自定义 ItemClickListener 接口

public interface ItemClickListener {
    void onItemClick(View view, int position);
    void onItemLongClick(View view, int position);
}

ItemClickSupport 类

ItemClickSupport 类负责将点击事件转发给 ItemClickListener。它通过为 RecyclerView 添加一个 ItemTouchHelper 来实现这一点。

public class ItemClickSupport {
    private RecyclerView recyclerView;
    private ItemClickListener itemClickListener;

    public ItemClickSupport(RecyclerView recyclerView, ItemClickListener itemClickListener) {
        this.recyclerView = recyclerView;
        this.itemClickListener = itemClickListener;
    }

    public void attach() {
        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
            @Override
            public int getMovementFlags(RecyclerView recyclerView, ViewHolder viewHolder) {
                return 0;
            }

            @Override
            public boolean onMove(RecyclerView recyclerView, ViewHolder viewHolder, ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(ViewHolder viewHolder, int direction) {
                // 不实现滑动功能
            }

            @Override
            public boolean isLongPressDragEnabled() {
                return false;
            }

            @Override
            public boolean isItemViewSwipeEnabled() {
                return false;
            }

            @Override
            public void onSelectedChanged(ViewHolder viewHolder, int actionState) {
                if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
                    viewHolder.itemView.setPressed(true);
                }
            }

            @Override
            public void clearView(RecyclerView recyclerView, ViewHolder viewHolder) {
                viewHolder.itemView.setPressed(false);
            }

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {
                if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
                    // 不实现拖拽功能
                }
            }
        });
        itemTouchHelper.attachToRecyclerView(recyclerView);
    }
}

实施子控件点击监听

现在,我们可以使用 ItemClickSupport 来监听 RecyclerView 表项子控件的点击事件:

recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        View child = rv.findChildViewUnder(e.getX(), e.getY());
        if (child != null) {
            ViewHolder holder = rv.getChildViewHolder(child);
            if (holder != null && itemClickListener != null) {
                itemClickListener.onItemClick(child, holder.getAdapterPosition());
                return true;
            }
        }
        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
        // 不需要实现
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
        // 不需要实现
    }
});

演示

现在,让我们用一个简单的示例来演示这种方法:

public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setAdapter(new MyAdapter(new ItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                // 处理表项点击事件
            }

            @Override
            public void onItemLongClick(View view, int position) {
                // 处理表项长按事件
            }
        }));

        ItemClickSupport.addTo(recyclerView);
    }
}

技术指南

  • 步骤 1: 创建 ItemClickListener 接口和 ItemClickSupport 类。
  • 步骤 2: 在 RecyclerView 中设置 ItemClickSupport。
  • 步骤 3: 在 onInterceptTouchEvent() 方法中,使用 findChildViewUnder() 查找被点击的视图。
  • 步骤 4: 使用 getChildViewHolder() 获取视图的 ViewHolder。
  • 步骤 5: 如果 ViewHolder 和 ItemClickListener 不为空,则触发点击事件。

示例代码

// ItemClickListener 接口
public interface ItemClickListener {
    void onItemClick(View view, int position);
    void onItemLongClick(View view, int position);
}

// ItemClickSupport 类
public class ItemClickSupport {
    private RecyclerView recyclerView;
    private ItemClickListener itemClickListener;

    public ItemClickSupport(RecyclerView recyclerView, ItemClickListener itemClickListener) {
        this.recyclerView = recyclerView;
        this.itemClickListener = itemClickListener;
    }

    public void attach() {
        recyclerView.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
            @Override
            public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                View child = rv.findChildViewUnder(e.getX(), e.getY());
                if (child != null) {
                    ViewHolder holder = rv.getChildViewHolder(child);
                    if (holder != null && itemClickListener != null) {
                        itemClickListener.onItemClick(child, holder.getAdapterPosition());
                        return true;
                    }
                }
                return false;
            }

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

            @Override
            public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
            }
        });
    }
}

// MyActivity 类
public class MyActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setAdapter(new MyAdapter(new ItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                // 处理表项点击事件
            }

            @Override
            public void onItemLongClick(View view, int position) {
                // 处理表项长按事件
            }
        }));

        ItemClickSupport.addTo(recyclerView);
    }
}

SEO