RecyclerViewでアクションを閉じるためにスワイプを実装しようとしていますが、ViewHolderの任意のビューでOnClickListenerを設定すると、そのビューのすべてのOnTouchイベントがオーバーライドされます。
OnClickListenerを放棄してTouchListenerのすべてのクリックを処理できますが、RecycleViewの子ビューに複数のボタンがある場合、それは多くのコードになり、これは正しい方法には見えません。
私のRecyleViewでは、スワイプでリスナーを却下するよう設定しています( これと同様 ):
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);
}
});
}
OnClickListener
内のボタンにViewHolder
を割り当て、タッチイベント用のインターフェイスを作成することでそれを実現しました。
サンプルプロジェクトはGitHubにあります: https://github.com/brnunes/SwipeableRecyclerView 。
私の場合、各アイテムは2つのボタンを持つCardView
であり、CardView
とButton
sのタッチイベントを検出したいです。 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
}