当前位置: 首页 > 知识库问答 >
问题:

句柄按钮单击回收站视图中的一行

微生恩
2023-03-14

我使用以下代码来处理行点击。(来源)

static 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) {
    }
}

然而,如果我想在每一行上都有一个删除按钮,这是可行的。我不知道如何用这个实现这一点。

我附加了OnClick侦听器来删除按钮,它可以工作(删除该行),但它也会在整行上触发onClick。

如果单击一个按钮,有谁能帮我避免整行单击吗。

谢谢。

共有3个答案

金阳曜
2023-03-14

我想要一个解决方案,该解决方案不创建任何额外的对象(即侦听器),这些对象稍后必须进行垃圾收集,并且不需要在适配器类中嵌套视图保持器。

在ViewHolder类中

private static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

        private final TextView ....// declare the fields in your view
        private ClickHandler ClickHandler;

        public MyHolder(final View itemView) {
            super(itemView);
            nameField = (TextView) itemView.findViewById(R.id.name);
            //find other fields here...
            Button myButton = (Button) itemView.findViewById(R.id.my_button);
            myButton.setOnClickListener(this);
        }
        ...
        @Override
        public void onClick(final View view) {
            if (clickHandler != null) {
                clickHandler.onMyButtonClicked(getAdapterPosition());
            }
        }

需要注意的是:定义了ClickHandler接口,但在这里没有初始化,因此在onClick方法中没有假设它曾经初始化过。

点击处理程序界面如下所示:

private interface ClickHandler {
    void onMyButtonClicked(final int position);
} 

在适配器中,在构造函数中设置“ClickHandler”的实例,并重写BindViewHolder,以初始化视图持有人上的“ClickHandler”:

private class MyAdapter extends ...{

    private final ClickHandler clickHandler;

    public MyAdapter(final ClickHandler clickHandler) {
        super(...);
        this.clickHandler = clickHandler;
    }

    @Override
    public void onBindViewHolder(final MyViewHolder viewHolder, final int position) {
        super.onBindViewHolder(viewHolder, position);
        viewHolder.clickHandler = this.clickHandler;
    }

注意:我知道那个viewHolder。clickHandler可能会使用完全相同的值多次设置,但这比检查null和分支要便宜,并且没有内存开销,只需要一条额外的指令

最后,在创建适配器时,您必须将ClickHandler实例传递给构造函数,如下所示:

adapter = new MyAdapter(new ClickHandler() {
    @Override
    public void onMyButtonClicked(final int position) {
        final MyModel model = adapter.getItem(position);
        //do something with the model where the button was clicked
    }
});

注意,适配器在这里是一个成员变量,而不是局部变量

宇文修筠
2023-03-14

我发现通常:

  • 我需要使用多个侦听器,因为我有几个按钮

因此@mark keen的答案很好,但有一个界面提供了更大的灵活性:

public static class MyViewHolder extends RecyclerView.ViewHolder {

    public ImageView iconImageView;
    public TextView iconTextView;

    public MyViewHolder(final View itemView) {
        super(itemView);

        iconImageView = (ImageView) itemView.findViewById(R.id.myRecyclerImageView);
        iconTextView = (TextView) itemView.findViewById(R.id.myRecyclerTextView);

        iconTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickListener.iconTextViewOnClick(v, getAdapterPosition());
            }
        });
        iconImageView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickListener.iconImageViewOnClick(v, getAdapterPosition());
            }
        });
    }
}

其中onClickListener在适配器中定义

public MyAdapterListener onClickListener;

public interface MyAdapterListener {

    void iconTextViewOnClick(View v, int position);
    void iconImageViewOnClick(View v, int position);
}

可能是通过构造器设置的:

public MyAdapter(ArrayList<MyListItems> newRows, MyAdapterListener listener) {

    rows = newRows;
    onClickListener = listener;
}

然后,您可以处理活动中的事件或使用RecyclerView的任何地方:

mAdapter = new MyAdapter(mRows, new MyAdapter.MyAdapterListener() {
                    @Override
                    public void iconTextViewOnClick(View v, int position) {
                        Log.d(TAG, "iconTextViewOnClick at position "+position);
                    }

                    @Override
                    public void iconImageViewOnClick(View v, int position) {
                        Log.d(TAG, "iconImageViewOnClick at position "+position);
                    }
                });
mRecycler.setAdapter(mAdapter);
谢灵均
2023-03-14

这是我在recyclerView中处理多个onClick事件的方式:

编辑:已更新以包含回调(如其他评论中提到的)。我在ViewHolder中使用了WeakResources来消除潜在的内存泄漏。

定义接口:

public interface ClickListener {

    void onPositionClicked(int position);
    
    void onLongClicked(int position);
}

然后适配器:

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder> {
    
    private final ClickListener listener;
    private final List<MyItems> itemsList;

    public MyAdapter(List<MyItems> itemsList, ClickListener listener) {
        this.listener = listener;
        this.itemsList = itemsList;
    }

    @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_row_layout), parent, false), listener);
    }

    @Override public void onBindViewHolder(MyViewHolder holder, int position) {
        // bind layout and data etc..
    }

    @Override public int getItemCount() {
        return itemsList.size();
    }

    public static class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {

        private ImageView iconImageView;
        private TextView iconTextView;
        private WeakReference<ClickListener> listenerRef;

        public MyViewHolder(final View itemView, ClickListener listener) {
            super(itemView);

            listenerRef = new WeakReference<>(listener);
            iconImageView = (ImageView) itemView.findViewById(R.id.myRecyclerImageView);
            iconTextView = (TextView) itemView.findViewById(R.id.myRecyclerTextView);

            itemView.setOnClickListener(this);
            iconTextView.setOnClickListener(this);
            iconImageView.setOnLongClickListener(this);
        }

        // onClick Listener for view
        @Override
        public void onClick(View v) {

            if (v.getId() == iconTextView.getId()) {
                Toast.makeText(v.getContext(), "ITEM PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(v.getContext(), "ROW PRESSED = " + String.valueOf(getAdapterPosition()), Toast.LENGTH_SHORT).show();
            }
            
            listenerRef.get().onPositionClicked(getAdapterPosition());
        }


        //onLongClickListener for view
        @Override
        public boolean onLongClick(View v) {

            final AlertDialog.Builder builder = new AlertDialog.Builder(v.getContext());
            builder.setTitle("Hello Dialog")
                    .setMessage("LONG CLICK DIALOG WINDOW FOR ICON " + String.valueOf(getAdapterPosition()))
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {

                        }
                    });

            builder.create().show();
            listenerRef.get().onLongClicked(getAdapterPosition());
            return true;
        }
    }
}

然后在您的活动/片段中-您可以实现的任何内容:Clicklistener-或者匿名类,如果您愿意的话:

MyAdapter adapter = new MyAdapter(myItems, new ClickListener() {
            @Override public void onPositionClicked(int position) {
                // callback performed on click
            }

            @Override public void onLongClicked(int position) {
                // callback performed on click
            }
        });

要获取单击的项目,请匹配视图id,即v.getId()==whateverItem。getId()

希望这种方法有帮助!

 类似资料:
  • 我有一个包含单选按钮的回收器视图。 现在我只想从列表中选择一个单选按钮并获得它的值 下面我附上了截图。 回收器视图的截图 下面是我到目前为止尝试的链接。 http://www.zoftino.com/android-recycerview-radiobutton 在回收视图中仅选择一个radiobutton 如何只选择一个RadioButton与RecolyerView Android? 从Rec

  • 我正在使用RecycerView构建一个切换按钮列表(如numpad),我希望实现: 当用户通过单击某个按钮“打开”该按钮时,将“关闭”所有其他按钮 我尝试在视图holder类中添加,并调用,这样就可以调用,然后更改按钮的状态。 维埃霍尔德 我的adpater类中的onBindViewHolder()

  • 请帮助如何使其工作

  • 单击时的卡片视图正在工作。但回收器视图的区域不可单击。如何使其可点击,以便捕获卡片视图的事件。

  • 如果用户点击一个,我希望它做一些事情,也为两个和三个。我如何实现这一点?

  • 我正在使用网格布局管理器使用回收器视图。我想在点击按钮时滚动循环视图。(单击按钮时,我正在通过位置,我的项目将突出显示)。所以我想在顶部显示突出显示的项目。可能是项目位于不同的位置。 onViewCreated在我初始化的位置----- 接口抽象方法---从我想滚动我的回收器视图和位置是从适配器类传递的。