web-dev-qa-db-fra.com

Événements Swipe et OnClick dans RecyclerView

J'essaie d'implémenter un balayage pour ignorer une action dans un RecyclerView, mais lorsque je définis un OnClickListener sur n'importe quelle vue dans un ViewHolder, il remplace tous les événements OnTouch de cette vue.

Je peux abandonner OnClickListener et gérer tous les clics dans TouchListener mais si j'ai plusieurs boutons dans une vue enfant de RecycleView, ce sera beaucoup de code et cela ne ressemble pas à la bonne façon.

Dans mon RecyleView, je configure Swipe pour rejeter les auditeurs ( similaire à ceci ):

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

Cela fonctionne dans le ListView, mais dans le RecycleView le OnClickListener bloque les événements OnTouchListner.

Exemple de mise en page pour la vue 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" />

Gonfler dans 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);
}

Le 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);
    }
    });
}
20
Ivan Fork

J'ai atteint cet objectif en affectant OnClickListener aux boutons du ViewHolder et en créant une interface pour les événements tactiles.

L'exemple de projet se trouve sur GitHub: https://github.com/brnunes/SwipeableRecyclerView .

Dans mon cas, chaque élément est un CardView avec deux boutons, et je veux détecter les événements tactiles dans les CardView et les Buttons. La disposition CardView ressemble à ceci:

<?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>

Puis dans le Activity, j'ai déclaré une interface pour recevoir les événements tactiles:

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

Et dans le ViewHolder j'affecte OnClickListeners aux objets que je veux écouter et j'appelle mon écouteur personnalisé:

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());
                }
            });
        }
    }
}

Enfin, instanciez le OnItemTouchListener personnalisé et passez-le au constructeur 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
}
22
brnunes