2014-10-29 18 views
19

Sto tentando di implementare uno scorrimento per eliminare l'azione in un RecyclerView ma quando imposto un OnClickListener su qualsiasi vista in un ViewHolder sostituisce tutti gli eventi OnTouch su quella vista.Scorri e eventi OnClick in RecyclerView

Posso abbandonare OnClickListener e gestire tutti i clic in TouchListener, ma se ho più pulsanti in una vista secondaria del RecycleView di quello sarà un sacco di codice e questo non sembra un modo giusto.

Nel mio RecyleView che sto impostando Swipe a respingere gli ascoltatori (similar to this):

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

Funziona in ListView, ma nelle RecycleView i blocchi OnClickListener OnTouchListner eventi.

Esempio di layout per vista 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" /> 

Gonfiando nella 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); 
} 

Il 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); 
    } 
    }); 
} 
+1

pubblicare il tuo codice di allora – pskink

+0

perché un sacco di codice? –

+0

Ho aggiunto il codice. –

risposta

22

ho raggiunto che assegnando OnClickListener per i pulsanti del ViewHolder, e creando un'interfaccia per gli eventi touch.

Il progetto di esempio è su GitHub: https://github.com/brnunes/SwipeableRecyclerView.

Nel mio caso ogni elemento è un CardView con due pulsanti, e voglio rilevare gli eventi di tocco del CardView ei Button s. Il layout CardView si presenta così:

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

Poi nel Activity, dichiarai un'interfaccia per ricevere gli eventi touch:

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

E nel ViewHolder assegno OnClickListeners agli oggetti che voglio ascoltare e chiamare il mio listener personalizzato:

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

Infine, istanziare l'usanza OnItemTouchListener e passarlo al costruttore 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 
} 
+0

Vorrei poter votare questo milione di volte! Il mio scorrimento è ancora un po 'scaglionato, a causa del caricamento delle immagini ... qualsiasi consiglio su questo sarebbe fantastico. : \ – marienke

+1

La soluzione è caricare l'immagine nella memoria in modo asincrono in un AsyncTask e quindi mostrarla in ImageView. Controlla questo articolo http://developer.android.com/training/improving-layouts/smooth-scrolling.html#AsyncTask. Questo post parla anche del caricamento asincrono. Nell'esempio le immagini vengono scaricate da Internet, ma è ancora più semplice se le stai caricando localmente: http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html – brnunes

+0

grazie per questo . – Tuss