9

Gibt es eine Möglichkeit, eine onClickListener auf eine RecyclerView zu setzen?Wie bekomme ich Klicks auf RecyclerView (NICHT die Kinder)

Ich habe ein RecyclerView mit einigen Kindern in ihnen, und auf dem übergeordneten RecyclerView ein OnClickListener Einstellung. Die onClick wird jedoch nicht ausgelöst, wenn ich auf diese Ansicht klicke. Siehe Beispielcode unten - wir möchten Klicks auf die Eltern, NICHT die Kinder bekommen. In diesem Szenario sind Klicks auf die Elemente nicht relevant.

Ich habe versucht, setFocusable(false), setClickable(false) und setOnClickListener(null) auf die Kinder ohne Erfolg zu tun. Auf jeden Fall glaube ich nicht, dass die Kinder Klicks von den Eltern klauen, denn wenn ich auf den Bereich klicke, in dem keine Kinder sind, werden auch die Klicks nicht registriert.

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

    } 

} 

Antwort

2

Gibt es eine Möglichkeit ein onClickListener auf einem RecyclerView zu setzen?

No. Das heißt, Sie können setzen ein OnClickListener, aber RecyclerView wird es nie nennen. RecyclerView fängt alle Berührungsereignisse ab, ruft aber niemals auf, wodurch View seinen Listener aufruft.

Sie können jedoch eine OnClickListener mit einer OnTouchListener und einer GestureDetector simulieren. Für den Listener GestureDetector können wir einen SimpleOnGestureListener verwenden, der nur die onSingleTapUp() Methode implementiert.

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

Dann brauchen wir nur die GestureDetector die MotionEvent s von einem OnTouchListener zu füttern, und überprüfen Sie die Rückkehr zu entscheiden, ob das Ereignis verbrauchen, um nicht mit Scrollen zu stören, Ziehen, usw.

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

Bitte beachten Sie, dass die obige Lösung nur mit einem "einfachen" RecyclerView funktioniert, wie in der Frage beschrieben und beschrieben. Wenn Sie eine komplexere Handhabung von Objekten verwenden, wie Ziehen und Ablegen oder Streichen, müssen wir unsere Gestenerkennung etwas weiter oben in der Touch-Ereigniskette handhaben.

Um dies zu tun, können wir RecyclerView Unterklasse und führen Sie die Erkennung in der dispatchTouchEvent() Methode. Wenn ein einzelnes Tippen erkannt wird, rufen Sie einfach an, wodurch OnClickListener ausgelöst wird.

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

Gerade diese Unterklasse anstelle Ihres regulären verwenden RecyclerView, und legen Sie eine OnClickListener auf, wie Sie es normalerweise tun würde.Je nachdem, wie Sie dies instanziieren, sind möglicherweise zusätzliche Konstruktoren erforderlich.

+1

das könnte haarig für uns werden. Wissen Sie, warum 'RecyclerView' nie' performClick' aufruft? –

+1

Nun, Sie müssten die Designer um eine definitive Antwort bitten, aber IMO, es ist, weil es nie so verwendet werden sollte. Wenn Sie dem Benutzer eine Liste präsentieren, sind Sie eher mit der Interaktion der einzelnen Elemente beschäftigt. Wie könnte das für dich haarig werden? Wenn Sie über den zusätzlichen Code besorgt sind, können Sie dies in einer 'RecyclerView'-Unterklasse implementieren, um den Code Ihrer' Aktivität 'nicht zu verschmutzen. Oder, wenn Sie meinen, dass Sie bereits Gesten verwenden, müsste diese Funktionalität nur zu dem hinzugefügt werden, was Sie bereits haben. –

+1

Wenn Sie Ihren 'OnClickListener' verwenden, können Sie' RecyclerView' von der Unterklasse '' performClick() 'selbst ableiten, aber Sie müssen die Berührungsereignisse verfolgen, um zwischen einem einfachen Klick zu unterscheiden und z. Ziehen, aber das ist im Grunde alles, was der GestureDetector sowieso macht. –

1

Probieren Sie etwas wie Ihr recyclerview in einem relativelayout oder Linearlayout oder FrameLayout Einwickeln und dann den Klick Zuhörer auf die 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> 

Jetzt:

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

dies funktioniert nicht für mich, funktioniert es für Sie? –

-1

ein Klickereignis auf RecycleView? versuchen Sie es so:

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

das funktioniert nicht für mich. funktioniert es für dich? –

Verwandte Themen