2015-05-24 5 views
7

Ich habe eine RecyclerView, die in einem CardView ist, die ein paar TextViews hat. Die CardView hat einen OnClickListener Satz und wird beim Klicken auf die TextViews abgefeuert, aber nicht beim Klicken auf den RecyclerView ausgelöst.Eltern-Klick-Ereignis wird nicht ausgelöst, wenn Recyclerview geklickt wurde

Hier ist, was die CardView wie folgt aussieht:

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

ich auf diesem RecyclerView keinen Klick Zuhörer brauchen und brauchen wirklich nur das Ereignis Click der übergeordneten Ansicht zu feuern, wenn der RecyclerView geklickt wird (Das gleiche gilt für das OnLongClick-Ereignis). Ich brauche auch den RecyclerView zum Scrollen. Ist der RecyclerView etwas wie das Klickereignis essen und es nicht an die Eltern weitergeben?

Antwort

0

@ywwynm, sind Sie auf dem richtigen Weg mit Ausnahme der Lösung nicht die verschachtelte RecyclerView erlauben zu blättern. Ich kombinierte es mit der Lösung here und entwickelte diese Lösung, um Click- und onLongClick-Ereignisse zu verarbeiten sowie Scrollen zu ermöglichen.

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

Der Nachteil dieses Ansatzes ist, dass der Selector der CardView nicht mehr verwendet wird, daher wird keine Rückmeldung von der CardView angezeigt. –

+0

Es verbrauchen auch Klicks, die die RecyclerView-Elemente gehen sollten. –

1

Ich habe herausgefunden, wie das Klickereignis an die Eltern von RecyclerView gelangt. Meine Lösung fühlt sich an wie ein Hack, also hoffe ich, dass jemand eine bessere Lösung finden kann.

Im 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; 
} 

Ich hatte dann das Click-Ereignis auf dem RecyclerView anschließen:

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

Es gibt eine bessere Lösung. Das heißt, eine Unterklasse Ihr 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

Danke, das funktioniert viel besser. Mein "Hack" funktionierte nicht, wenn der Benutzer auf den Teil der Recycler-Ansicht klickte, in dem sich keine Elemente befanden. Diese Lösung behebt dieses Problem. – Daryl

+0

Diese Antwort muss akzeptiert werden –

5
recyclerView.setLayoutFrozen(true); 

nur setLayoutFrozen wahr nach setAdapter für recyclerView

+1

Diese Methode verhindert, dass RecyclerView aktualisiert wird - Adapter "onBindViewHolder" wird unter bestimmten Umständen nicht aufgerufen. – peppered

+0

Vielen Dank Thomas diese Methode hilft mir wirklich mein Problem zu lösen .. – Nitin

0

In meinem Fall hatte ich eine CardView mit ein paar Tasten und ein RecyclerView. Bei den Lösungen ywwynm und Daryl bestand das Problem darin, dass CardView die Ereignisse aller untergeordneten Ansichten einschließlich der Schaltflächen abfangen würde. Aber ich wollte, dass CardView nur die Touch-Ereignisse des RecyclerViews abfängt. Meine Lösung war folgende:

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