【问题标题】:Swipe and OnClick events in RecyclerViewRecyclerView 中的 Swipe 和 OnClick 事件
【发布时间】:2014-12-25 03:14:20
【问题描述】:

我正在尝试在 RecyclerView 中实现滑动以关闭操作,但是当我在 ViewHolder 中的任何视图上设置 OnClickListener 时,它会覆盖该视图上的所有 OnTouch 事件。

我可以放弃 OnClickListener 并处理 TouchListener 中的所有点击,但如果我在 RecycleView 的子视图中有多个按钮,那将是很多代码,而且这看起来不是正确的方法。

在我的 RecyleView 中,我将 Swipe 设置为关闭听众 (similar to this):

    setOnTouchListener(touchListener);
    setOnScrollListener(touchListener.makeScrollListener());

它在 ListView 中有效,但在 RecycleView 中,OnClickListener 会阻止 OnTouchListner 事件。

ViewHolder 视图的布局示例。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="72dp"
android:descendantFocusability="blocksDescendants">

<ImageView
    android:id="@+id/keep_icon"
    android:layout_width="48dp"
    android:layout_height="48dp"
    android:layout_centerInParent="true"
    android:src="@drawable/ic_received" />

在 RecyclerView.Adapter 中充气:

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
    View v = mInflater.inflate(R.layout.push_card_view_compat, viewGroup, false);
    return new ViewHolder(v, onClickListener, onKeepListener);
}

ViewHolder:

public ViewHolder(final View itemView,
                  final OnViewHolderClickListener onClickListener,
                  final OnKeepListener onKeepListener) {
    super(itemView);
    keepButton = (ImageView) itemView.findViewById(R.id.keep_icon);

    itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        onItemClickListener.onClick(getPosition(), itemView);
    }
    });
    keepButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        onKeepListener.onClick(getPosition(), itemView);
    }
    });
}

【问题讨论】:

  • 尝试将行项目添加到您的 xml 外部 ViewGroup 中:android:descendantFocusability="blocksDescendants"
  • @inner_class7 没用。
  • 您是否将此添加到您的视图持有者的父元素中?
  • 是的,我也尝试过“afterDescendants”,但都没有成功。
  • @IvanFork 它就像 ViewGroup 的触摸事件:你有 onInterceptTouchEvent 和 OnTouchEvent

标签: android swipe ontouchlistener android-recyclerview


【解决方案1】:

我通过为ViewHolder 中的按钮分配OnClickListener 并为触摸事件创建一个界面来实现这一点。

示例项目在 GitHub 上:https://github.com/brnunes/SwipeableRecyclerView

在我的例子中,每个项目都是一个带有两个按钮的CardView,我想检测CardViewButtons 中的触摸事件。 CardView 布局如下所示:

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="5dp"
    android:clickable="true"
    android:foreground="?android:attr/selectableItemBackground"
    android:orientation="vertical"
    card_view:cardCornerRadius="5dp">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/card_view_title"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:textColor="@android:color/black"
            android:textSize="24sp" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_below="@id/card_view_title"
            android:layout_centerHorizontal="true"
            android:gravity="center">

            <Button
                android:id="@+id/card_view_button1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button1" />

            <Button
                android:id="@+id/card_view_button2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button2" />
        </LinearLayout>
    </RelativeLayout>

</android.support.v7.widget.CardView>

然后在Activity中声明了一个接口来接收触摸事件:

public interface OnItemTouchListener {
    public void onCardViewTap(View view, int position);
    public void onButton1Click(View view, int position);
    public void onButton2Click(View view, int position);
}

ViewHolder 中,我将OnClickListeners 分配给我想收听的对象,并调用我的自定义侦听器:

public class CardViewAdapter extends RecyclerView.Adapter<CardViewAdapter.ViewHolder> {
    private List<String> cards;
    private OnItemTouchListener onItemTouchListener;

    public CardViewAdapter(List<String> cards, OnItemTouchListener onItemTouchListener) {
        this.cards = cards;
        this.onItemTouchListener = onItemTouchListener;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
        View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.card_view_layout, viewGroup, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int i) {
        viewHolder.title.setText(cards.get(i));
    }

    @Override
    public int getItemCount() {
        return cards == null ? 0 : cards.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView title;
        private Button button1;
        private Button button2;

        public ViewHolder(View itemView) {
            super(itemView);
            title = (TextView) itemView.findViewById(R.id.card_view_title);
            button1 = (Button) itemView.findViewById(R.id.card_view_button1);
            button2 = (Button) itemView.findViewById(R.id.card_view_button2);

            button1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onItemTouchListener.onButton1Click(v, getPosition());
                }
            });

            button2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onItemTouchListener.onButton2Click(v, getPosition());
                }
            });

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    onItemTouchListener.onCardViewTap(v, getPosition());
                }
            });
        }
    }
}

最后,实例化自定义的OnItemTouchListener 并将其传递给CardViewAdapter 构造函数:

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

    mItems = new ArrayList<>(30);
    for (int i = 0; i < 30; i++) {
        mItems.add(String.format("Card number %2d", i));
    }

    OnItemTouchListener itemTouchListener = new OnItemTouchListener() {
        @Override
        public void onCardViewTap(View view, int position) {
            Toast.makeText(MainActivity.this, "Tapped " + mItems.get(position), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onButton1Click(View view, int position) {
            Toast.makeText(MainActivity.this, "Clicked Button1 in " + mItems.get(position), Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onButton2Click(View view, int position) {
            Toast.makeText(MainActivity.this, "Clicked Button2 in " + mItems.get(position), Toast.LENGTH_SHORT).show();
        }
    };

    mAdapter = new CardViewAdapter(mItems, itemTouchListener);

    mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);

    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    mRecyclerView.setAdapter(mAdapter);

    // ... Assign the swipe listener
}

【讨论】:

  • 我希望我能投票上百万次!由于加载图像,我的滚动仍然有点交错......任何建议都会很棒。 :\
  • 解决方法是在AsyncTask中将图片异步加载到内存中,然后在ImageView中展示出来。查看这篇文章developer.android.com/training/improving-layouts/…。这篇文章还讨论了异步加载。在示例中,图像是从 Internet 下载的,但如果您在本地加载它们会更简单:android-developers.blogspot.com/2010/07/…
猜你喜欢
  • 2021-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 2016-09-07
  • 2017-08-27
  • 1970-01-01
相关资源
最近更新 更多