9

C'è un modo per impostare uno onClickListener su un RecyclerView?Come ottenere clic su RecyclerView (NON i bambini)

Ho un RecyclerView con alcuni bambini al suo interno e l'impostazione di OnClickListener sul genitore RecyclerView. Tuttavia, lo onClick non si attiva quando faccio clic su quella vista. Vedi il codice di esempio qui sotto - vogliamo ottenere clic sul genitore, NON i bambini. In questo scenario non ci interessano i clic sugli articoli.

Ho provato a fare setFocusable(false), setClickable(false) e setOnClickListener(null) sui bambini senza successo. In ogni caso, non penso che i bambini stiano rubando i clic dal genitore, perché quando clicco sull'area in cui non ci sono bambini, i clic non si registrano neanche.

package com.formagrid.hellotest; 

import android.app.Activity; 
import android.os.Bundle; 
import android.support.v7.widget.LinearLayoutManager; 
import android.support.v7.widget.RecyclerView; 
import android.util.Log; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

import java.util.Arrays; 
import java.util.List; 

public class HelloActivity extends Activity { 

    private RecyclerView mRecyclerView; 
    private RecyclerAdapter mAdapter; 

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

     mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view); 
     mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 
     mAdapter = new RecyclerAdapter(Arrays.asList("hi", "this", "is", "some", "text")); 
     mRecyclerView.setAdapter(mAdapter); 
     mRecyclerView.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View view) { 
       Log.d("patricia", view.toString()); 
      } 
     }); 
    } 

    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
    } 

    @Override 
    protected void onPause() { 
     super.onPause(); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 
    } 

    public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.Holder> { 

     public class Holder extends RecyclerView.ViewHolder { 

      protected TextView textView; 

      public Holder(TextView itemView) { 
       super(itemView); 
       this.textView = itemView; 
      } 

     } 

     private List<String> contents; 

     public RecyclerAdapter(List<String> contents) { 
      this.contents = contents; 
     } 

     @Override 
     public Holder onCreateViewHolder(ViewGroup parent, int viewType) { 
      return new Holder(new TextView(parent.getContext())); 
     } 

     @Override 
     public void onBindViewHolder(Holder holder, int position) { 
      holder.textView.setText(contents.get(position)); 
     } 

     @Override 
     public int getItemCount() { 
      return contents.size(); 
     } 

    } 

} 

risposta

2

Esiste un modo per impostare un onClickListener su un RecyclerView?

No. Questo è, si può impostare un OnClickListener, ma RecyclerView sarà mai chiamarlo. RecyclerView intercetta tutti gli eventi di tocco, ma non chiama mai performClick(), ovvero il modo in cui View richiama il relativo listener.

È tuttavia possibile simulare uno con uno OnTouchListener e uno GestureDetector. Per il listener di GestureDetector, è possibile utilizzare uno SimpleOnGestureListener, che implementa solo il metodo onSingleTapUp().

class ClickListener extends GestureDetector.SimpleOnGestureListener { 
    @Override 
    public boolean onSingleTapUp(MotionEvent e) { 
     Toast.makeText(HelloActivity.this, "Clicked", 0).show(); 
     return true; 
    } 
}; 

Poi abbiamo solo bisogno di alimentare le GestureDetector i MotionEvent s da un OnTouchListener, e controllare il ritorno di decidere se consumare l'evento, in modo da non interferire con lo scorrimento, trascinando, ecc

final GestureDetector detector = new GestureDetector(HelloActivity.this, new ClickListener()); 

mRecyclerView.setOnTouchListener(new OnTouchListener() { 
     @Override 
     public boolean onTouch(View v, MotionEvent event) { 
      if(detector.onTouchEvent(event)) { 
       return true; 
      } 
      return false; 
     } 
    } 
); 

Si prega di notare che la soluzione di cui sopra funziona praticamente solo con un "semplice" RecyclerView, come quello descritto e indicato nella domanda. Se stai utilizzando una gestione degli articoli più complessa, come trascina e rilascia o scorri, dovremo gestire il rilevamento dei gesti un po 'più in alto nella catena di eventi touch.

Per fare ciò, è possibile creare sottoclasse RecyclerView ed eseguire il rilevamento nel metodo dispatchTouchEvent(). Se viene rilevato un singolo tocco, chiamiamo semplicemente performClick(), che genera il RecyclerView .

public class ClickableRecyclerView extends RecyclerView { 

    private final GestureDetectorCompat detector; 

    public ClickableRecyclerView(Context context) { 
     this(context, null); 
    } 

    public ClickableRecyclerView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     detector = new GestureDetectorCompat(context, new ClickListener()); 
    } 

    private class ClickListener extends GestureDetector.SimpleOnGestureListener { 
     @Override 
     public boolean onSingleTapUp(MotionEvent e) { 
      performClick(); 
      return true; 
     } 
    }; 

    @Override 
    public boolean dispatchTouchEvent(MotionEvent e) { 
     detector.onTouchEvent(e); 
     return super.dispatchTouchEvent(e); 
    } 
} 

basta usare questo sottoclasse al posto del vostro regolare RecyclerView, e impostare un OnClickListener su di essa come si farebbe normalmente.Potrebbero essere necessari ulteriori costruttori, a seconda di come si sta creando un'istanza di questo.

+1

che potrebbe diventare peloso per noi. ti capita di sapere perché 'RecyclerView' non chiama mai 'performClick'? –

+1

Beh, dovresti chiedere ai designer una risposta definitiva, ma IMO, è perché non è mai stato pensato per essere usato in quel modo. Di solito quando si presenta all'utente un elenco, si è più interessati all'interazione sui singoli elementi. Come potrebbe questo diventare peloso per te? Se sei preoccupato per il codice extra, puoi implementarlo in una sottoclasse 'RecyclerView', in modo da non inquinare il codice di 'Activity'. Oppure, se intendi che stai già utilizzando i gesti, questa funzionalità dovrebbe solo essere aggiunta a ciò che hai già. –

+1

Se sei morto impostato sull'uso di 'OnClickListener', puoi eseguire la sottoclasse di' RecyclerView' per chiamare 'performClick()' stesso, ma dovrai monitorare gli eventi di tocco per distinguere tra un semplice clic e, ad esempio, trascinando, ma questo è fondamentalmente tutto il 'GestureDetector' sta facendo comunque. –

1

provare qualcosa di simile avvolgere il vostro recyclerview all'interno di un relativelayout o LinearLayout o FrameLayout e quindi impostare il clic ascoltatore alla relativelayout/LinearLayout/framelayout.

<RelativeLayout 
    android:id="@+id/myLayout" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content"> 
    <android.support.v7.widget.RecyclerView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 
    </android.support.v7.widget.RecyclerView> 
</RelativeLayout> 

Ora:

RelativeLayout rl = (RelativeLayout) findViewById(R.id.myLayout); 
rl.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View view) { 
     Log.d("patricia", view.toString()); 
    } 
}); 
+1

questo non funziona per me, funziona per voi? –

-1

un evento click su RecycleView? provare in questo modo:

//set android:descendantFocusability="blocksDescendants" on parent layout 
//then setOnClickListener 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:orientation="vertical" 
android:layout_width="match_parent" 
**android:descendantFocusability="blocksDescendants"** 
android:layout_height="match_parent"> 

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

</LinearLayout> 
+1

questo non funziona per me. Per te funziona? –