如何使RecyclerView不可点击并将onClick事件传递给父视图?

27

如何让RecyclerView不可点击?因为我的RecyclerView只显示一些小图标,而这些图标位于可以被点击的CardView内部。所以如果有人点击这些图标,应该只会触发它们父级的CardView的点击(和动画)。

我已经尝试了以下方法:

  1. recyclerView.setClickable(false);
  2. recyclerView.setFocusable(false);
  3. 扩展RecyclerView并使onTouchEvent(MotionEvent)返回false
  4. 使用上述方法3,并在RecyclerView适配器中使用itemView.setClickable(false);。 这个方法有效,点击事件被发送到了父级。但是,现在RecyclerView不再可滚动。
  5. 在膨胀的列表项XML中设置clickable="false"focusable="false"focusableInTouchMode="false"。(参见评论@Ibrahim
  6. 调用recyclerView#setLayoutFrozen(true)itemView.setClickable(false);。 这个方法有效,但具有与#4相同的问题。

有什么好的方法可以禁用并将RecyclerView的点击事件传递给父视图吗?请注意,RecyclerView仍然需要可滚动(水平方向)。


编辑:
用户@c.dunlap建议为图标设置OnClick监听器,并将点击“重定向”到父级的点击操作。这样做是可行的,但父级视图将没有点击动画。而且,如果有人在itemView外面点击--但仍然在RecyclerView内(例如,ItemDecoration padding),则不会检测到该点击。因此,很遗憾这不是一个解决办法。


@VladoPandžić 适配器并没有什么特别的地方。它像正常一样填充布局。onBindViewHolder(...) 中唯一的代码是将 Drawable 设置到 ImageView 上。 - Thomas Vos
1
你尝试在充气的布局XML中将clickablefocusablefocusableontouchmode设置为false了吗? - user6490462
@Ibrahim 刚刚尝试了,没有任何改变。 - Thomas Vos
同时在回收视图的 xml 上尝试使用 clickable="false"focusable="false" 和 **focusableInTouchMode="false"**,如果可用,则提供回收视图的点击实现。 - user6490462
@Ibrahim,你看到我的问题了吗?请查看第1和第2项。你能解释一下什么是RecyclerView点击实现吗? - Thomas Vos
显示剩余6条评论
3个回答

18

你应该扩展父视图并拦截点击事件,这样RecyclerView就不会接收到它。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    return true;
}

感谢:解决方案


这是最佳的工作解决方案。应该标记为答案。 - Skullper
这样做会不会阻止RecyclerView的滚动? - android developer

3

我处理这类问题的首选方式是从适配器中附加监听器,当您的RecyclerView中的每个图标被点击时,该监听器将被调用。然后,您的活动可以以适当的方式做出响应。例如:

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private MyAdapterListener mListener;

    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
         holder.itemView.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 mListener.iconClicked();
             }
         });
    }

    public void setListener(MyAdapterListener listener) {
        mListener = listener;
    }

    public interface MyAdapterListener {
        void iconClicked();
    }

}

然后在您的活动中,您可以简单地创建MyAdapterListener的实例,并将其设置为您的Recycler View适配器的侦听器。然后当 iconClicked() 函数被触发时,执行与父级单击相同的代码。


2
感谢您的回答。这个方法可以,但是父视图上不会有点击动画。而且,如果有人在“itemView”之外单击怎么办?我该如何处理这种情况? - Thomas Vos
请查看我问题的“编辑”部分。 - Thomas Vos
如果您修改了itemViews,使它们在recyclerView中没有任何间距,而是在itemView内部有填充,则您的itemViews将填充recyclerView,从而无法单击recyclerView但不是itemView。如果您正在执行其他使此操作不可行的操作,则可能需要共享您的布局,以便我们可以为您提供进一步帮助。个人而言,我发现这种方法通常会导致更好的布局(单元格之间的均匀间距)。 - c.dunlap
1
问题不是itemView之间有空隙。就像你说的,我可以通过在itemView布局中使用填充来解决这个问题。问题是如果只有几个“图标”,那么并没有使用整个RecyclerView,仍然有剩余空间。我无法将RecyclerView设置为wrap_content,因为它需要位于其他两个视图之间。所以我认为你的答案对我的情况不起作用。还有其他解决方案吗? - Thomas Vos
你能分享一下你的布局吗? - c.dunlap
这将不允许在RecyclerView的父级上产生点击效果。 - android developer

-2

我遇到了同样的问题,在尝试多种方法后,我在recyclerview上使用了一个额外的布局。

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.RecyclerView
        android:layoutwidth="match_parent"
        android:layout_height="match_parent">
    </android.support.v7.widget.RecyclerView>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</RelativeLayout>

之后你可以让 "LinearLayout" 可见或不可见。 这个方法百分之百有效。


1
这是如何工作的?你能解释一下它是如何解决问题的吗? - Thomas Vos
当您想要禁用recyclerview时,可以将LinearLayout设置为可见,当LinearLayout可见时,recyclerview将无法工作,然后您可以隐藏该LinearLayout以使recyclerview重新启用。 - Deepak Tiwari
好的,我明白了,但那不是我的问题。我的问题是如何禁用RecyclerView并将点击事件传递给父视图。我还注意到RecyclerView仍然需要可滚动。如果我只想禁用RecyclerView,我可以在RecyclerViewitemView上使用setEnabled(false),但这样点击事件就无法传递给父布局了。 - Thomas Vos
你能上传你的XML文件吗?我会给出正确的答案。 - Deepak Tiwari
@ThomasVos 这个方法可行是因为LinearLayout遮盖了整个RecyclerView,并接收了点击事件。 - Brill Pappin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接