2015-05-24 17 views
7

Ho un RecyclerView che è in un CardView che ha un paio di TextViews. CardView ha un set OnClickListener e viene attivato quando si fa clic su TextViews, ma non si attiva quando si fa clic su RecyclerView.Genitore evento click non sparato quando ricicla cliccato

Ecco ciò che il CardView assomiglia:

<?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:id="@+id/card_view" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:layout_margin="5dp" 
    card_view:cardCornerRadius="4dp" 
    card_view:cardElevation="5dp"> 

    <LinearLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     android:orientation="vertical" 
     android:weightSum="100" 
     android:minWidth="100dp"> 

     <TextView 
      android:layout_width="wrap_content" 
      android:layout_height="wrap_content" 
      android:textAppearance="?android:attr/textAppearanceLarge" 
      android:id="@+id/text1" 
      android:textColor="@color/abc_primary_text_material_light" 
      android:layout_weight="1" 
      android:layout_gravity="center_horizontal" /> 

     <android.support.v7.widget.RecyclerView 
      android:id="@+id/recyclerView" 
      android:layout_width="match_parent" 
      android:layout_height="0dp" 
      android:listSelector="@color/highlighted_text_material_light" 
      android:layout_weight="98" /> 

     <View 
      android:layout_width="match_parent" 
      android:layout_height="1dp" 
      android:background="@android:color/black" /> 

     <RelativeLayout 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:id="@+id/relativeSummary" 
      android:orientation="horizontal" 
      android:layout_weight="1"> 

      <TextView 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:textAppearance="?android:attr/textAppearanceLarge" 
       android:id="@+id/text2" 
       android:textAlignment="viewEnd" 
       android:textColor="@color/abc_secondary_text_material_light" 
       android:layout_marginLeft="5dp" 
       android:layout_marginRight="5dp" 
       android:gravity="start" 
       android:singleLine="true" 
       android:layout_alignParentLeft="true" /> 

      <TextView 
       android:layout_width="wrap_content" 
       android:layout_height="wrap_content" 
       android:textAppearance="?android:attr/textAppearanceLarge" 
       android:id="@+id/text3" 
       android:textColor="@color/abc_primary_text_material_light" 
       android:layout_marginRight="5dp" 
       android:layout_marginLeft="5dp" 
       android:gravity="end" 
       android:singleLine="true" 
       android:layout_alignParentRight="true" 
       android:layout_toRightOf="@+id/text2" /> 

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

Non ho bisogno di uno scatto ascoltatore su questo RecyclerView e davvero solo bisogno di evento click del vista padre a fuoco quando il RecyclerView si fa clic (Lo stesso vale per l'evento OnLongClick). Ho anche bisogno di RecyclerView per scorrere. Il RecyclerView mostra in che modo mangiare l'evento click e non trasmetterlo al genitore?

risposta

0

@ywwynm, siete sulla strada giusta, tranne la soluzione non permette il RecyclerView nidificato per scorrere. L'ho combinato con la soluzione here e ho trovato questa soluzione per gestire gli eventi click e onLongClick e per consentire lo scorrimento.

public class InterceptTouchCardView extends CardView { 
    private GestureDetector mGestureDetector; 
    private boolean mLongClicked; 

    public InterceptTouchCardView(Context context) { 
     super(context); 
     Initialize(); 
    } 

    public InterceptTouchCardView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     Initialize(); 
    } 

    public InterceptTouchCardView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     Initialize(); 
    } 

    private void Initialize() { 
     mGestureDetector = new GestureDetector(getContext(), 
       new GestureDetector.SimpleOnGestureListener() { 
        public boolean onDown(MotionEvent e) { 
         mLongClicked = false; 
         return true; 
        } 

        public void onLongPress(MotionEvent e) { 
         mLongClicked = true; 
         performLongClick(); 
        } 
       }); 
    } 

    /** 
    * Intercept touch event so that inner views cannot receive it. 
    * 
    * If a ViewGroup contains a RecyclerView and has an OnTouchListener or something like that, 
    * touch events will be directly delivered to inner RecyclerView and handled by it. As a result, 
    * parent ViewGroup won't receive the touch event any longer. 
    * 
    * We can't Intercept the touch event if we want to allow scrolling since ACTION_DOWN always 
    * happens before ACTION_MOVE. So handle touch events here since onTouchEvent won't be triggered. 
    */ 
    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     mGestureDetector.onTouchEvent(ev); 
     if (ev.getAction() == MotionEvent.ACTION_UP && !mLongClicked) 
      this.callOnClick(); 
     return false; 
    } 
} 
+0

Lo svantaggio di questo approccio è che il selettore del CardView non sarà più utilizzato, quindi nessun feedback del CardView non verrà mostrato. –

+0

Consuma anche i clic che dovrebbero andare agli elementi di RecyclerView. –

1

Ho scoperto come ottenere l'evento click sul genitore di RecyclerView. La mia soluzione sembra un trucco, quindi spero che qualcuno possa trovare una soluzione migliore.

Nella RecylerView.Adapter:

@Override 
public ViewHolder onCreateViewHolder(final ViewGroup viewGroup, int i) { 
    View view = LayoutInflater.from(viewGroup.getContext()) 
      .inflate(R.layout.my_item_layout, viewGroup, false); 

    ViewHolder viewHolder = new ViewHolder(view); 

    viewHolder.itemView.setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      viewGroup.callOnClick(); 
     } 
    }); 
    viewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 
     @Override 
     public boolean onLongClick(View v) { 
      return viewGroup.performLongClick(); 
     } 
    }); 

    return viewHolder; 
} 

Poi ho dovuto collegare l'evento click sul RecyclerView:

RecyclerView.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View v) { 
     parentView.callOnClick(); 
    } 
}); 
RecyclerView.setOnLongClickListener(new View.OnLongClickListener() { 
    @Override 
    public boolean onLongClick(View v) { 
     return parentView.performLongClick(); 
    } 
}); 
5

C'è una soluzione migliore. Cioè, sottoclasse tua CardView:

public class InterceptTouchCardView extends CardView { 

    public InterceptTouchCardView(Context context) { 
     super(context); 
    } 

    public InterceptTouchCardView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public InterceptTouchCardView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    /** 
    * Intercept touch event so that inner views cannot receive it. 
    * 
    * If a ViewGroup contains a RecyclerView and has an OnTouchListener or something like that, 
    * touch events will be directly delivered to inner RecyclerView and handled by it. As a result, 
    * parent ViewGroup won't receive the touch event any longer. 
    */ 
    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     return true; 
    } 
} 
+0

Grazie, funziona molto meglio. Il mio "hack" non funzionava quando l'utente faceva clic sulla parte del recyclerview dove non c'erano elementi. Questa soluzione risolve questo problema. – Daryl

+0

Questa risposta deve essere accettata –

5
recyclerView.setLayoutFrozen(true); 

solo setLayoutFrozen vero dopo setAdapter per recyclerView

+1

Questo metodo impedisce l'aggiornamento di RecyclerView - la scheda 'onBindViewHolder' non verrà chiamata in alcune circostanze. – peppered

+0

grazie mille Thomas questo metodo mi aiuta davvero a risolvere il mio problema .. – Nitin

0

Nel mio caso, ho avuto un CardView con un paio di pulsanti e un RecyclerView. Con le soluzioni di ywwynm e Daryl il problema era che il CardView intercettava gli eventi da tutte le sue viste secondarie, inclusi i pulsanti. Ma quello che volevo era che CardView intercettasse solo gli eventi touch di RecyclerView. La mia soluzione era la seguente:

public class UntouchableRecyclerView extends RecyclerView { 

    public UntouchableRecyclerView(Context context) { 
     super(context); 
    } 

    public UntouchableRecyclerView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public UntouchableRecyclerView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent e) { 
     return false; 
    } 
} 
Problemi correlati