2014-10-29 31 views
19

Próbuję zaimplementować przesunięcie w celu odrzucenia akcji w RecyclerView, ale gdy ustawię OnClickListener w dowolnym widoku w ViewHolder, zastępuje on wszystkie zdarzenia OnTouch w tym widoku.Zdarzenia Swipe i OnClick w RecyclerView

Mogę zrezygnować z OnClickListener i obsłużyć wszystkie kliknięcia w TouchListener, ale jeśli mam wiele przycisków w widoku podrzędnym RecycleView, to będzie dużo kodu i nie wygląda to tak, jak należy.

W moim RecyleView mam ustawienie Przesuń, by zamknąć słuchaczy (similar to this):

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

Działa w ListView, ale w RecycleView bloków OnClickListener OnTouchListner wydarzeń.

Przykład układu dla widoku 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" /> 

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

The 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

pisać kod następnie – pskink

+0

dlaczego dużo kodu? –

+0

Dodałem kod. –

Odpowiedz

22

osiągnąłem że przypisując OnClickListener dla przycisków w ViewHolder oraz tworzenie interfejs dla zdarzeń dotykowych.

Przykładowy projekt znajduje się na GitHub: https://github.com/brnunes/SwipeableRecyclerView.

W moim przypadku każdy element to CardView z dwoma przyciskami i chcę wykryć zdarzenia dotyku w i Button s. Układ CardView wygląda następująco:

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

Następnie w Activity, oświadczyłem interfejs do odbierania zdarzeń dotykowy:

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

A w ViewHolder przypisać OnClickListeners do obiektów, które chcę słuchać, i zadzwonić do mojego własnego słuchacza:

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

Wreszcie wystąpienia zwyczaj OnItemTouchListener i przekazać go do konstruktora 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

Chciałbym móc głosować na to milion razy! Moje przewijanie jest nadal nieco rozłożone, ponieważ ładowanie obrazów ... każda rada byłaby świetna. : \ – marienke

+1

Rozwiązaniem jest załadowanie obrazu do pamięci asynchronicznie w AsyncTask, a następnie wyświetlenie go w ImageView. Sprawdź ten artykuł http://developer.android.com/training/improving-layouts/smooth-scrolling.html#AsyncTask. Ten post również mówi o ładowaniu asynchronicznym. W tym przykładzie obrazy są pobierane z internetu, ale jest jeszcze prostsze, jeśli ładujesz je lokalnie: http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html – brnunes

+0

dzięki za to . – Tuss