2016-05-26 22 views
12

W jednym z moich poprzednich questions, zapytałem (i odpowiedziałem sobie po wpisie na blogu this), w jaki sposób poprawnie obsłużyć kluczowe wejście na RecyclerView.Dodanie poprawnej obsługi klawiatury do RecyclerView

Teraz zdałem sobie sprawę, że jeśli trzymać wciśnięty klawisz strzałki, powiedzmy w dół klucza, przewijanie w dół zatrzymuje i RecyclerView traci ostrość, prawdopodobnie dlatego, że przewijanie jest szybsze niż wytwarzanie wszystkich dzieci View s.

Czy istnieje jakieś obejście lub lepsza praktyka w prawidłowym obsługiwaniu wejść klawiatury sprzętowej w urządzeniu RecyclerView?

Aktualizacja:

wydałem podstawowy przykład here, to działa bez zarzutu teraz, nie ma bardziej skupić straty.

+2

Do masz [mcve]? Właśnie dodałem obsługę klawiatury do wczoraj 'RecyclerView', podobnie jak to robiłeś. W moim przypadku jest to pełnoekranowy widok "RecyclerView", więc nie miałem żadnych problemów z ustawieniem ostrości. Łatwiej będzie ludziom pomóc w rozwiązaniu problemu, jeśli mamy konkretną implementację problemu. – CommonsWare

+0

@CommonsWare utworzę mój przykład jak najszybciej. Myślę, że możesz spróbować dodać widok z możliwością ustawiania ostrości (np. Przycisk) poniżej swojego RecyclerView i użyć dużego zestawu danych w adapterze, powiedzmy, 100 elementów. Powinieneś zobaczyć ostrość zachowując się dziwnie. – Vektor88

+0

Będę szturchnął to bardziej jutro. Widziałem inne dziwne wyniki (np. Efekt rozmazywania). Myślę, że być może powinniśmy poczekać, aby zaktualizować 'RecyclerView' po raz drugi, aż po zakończeniu przetwarzania, a nie po jednym zdarzeniu kluczowym. Wszystko, co jest powiedziane, mając widok, który można ustawić pod listą przewijaną w pionie, nie jest dobrym UX na klawiaturze. Będziesz rozmawiać o tego rodzaju rzeczach w zakresie pisania aplikacji dla Android TV (lub jego poprzednika Google TV, Fire TV, itp.). – CommonsWare

Odpowiedz

4

udało mi się zaimplementować klasę abstrakcyjną Adapter zdolnego śledzenie wybranej pozycji bez utraty punkt ostrości, projekt próbki można znaleźć here specyficzna implementacja klasy adaptera jest poniżej:

import android.content.Context; 
import android.support.v7.widget.RecyclerView; 
import android.view.KeyEvent; 
import android.view.View; 


/** 
* Created by vektor on 31/05/16. 
*/ 
public abstract class InputTrackingRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH>{ 

    private Context mContext; 
    private int mSelectedItem = 0; 
    private RecyclerView mRecyclerView; 

    public InputTrackingRecyclerViewAdapter(Context context){ 
     mContext = context; 
    } 

    @Override 
    public void onAttachedToRecyclerView(final RecyclerView recyclerView) { 
     super.onAttachedToRecyclerView(recyclerView); 

     mRecyclerView = recyclerView; 
     // Handle key up and key down and attempt to move selection 
     recyclerView.setOnKeyListener(new View.OnKeyListener() { 
      @Override 
      public boolean onKey(View v, int keyCode, KeyEvent event) { 
       RecyclerView.LayoutManager lm = recyclerView.getLayoutManager(); 

       // Return false if scrolled to the bounds and allow focus to move off the list 
       if (event.getAction() == KeyEvent.ACTION_DOWN) { 
        if (isConfirmButton(event)) { 
         if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) == KeyEvent.FLAG_LONG_PRESS) { 
          mRecyclerView.findViewHolderForAdapterPosition(mSelectedItem).itemView.performLongClick(); 
         } else { 
          event.startTracking(); 
         } 
         return true; 
        } 
        else { 
         if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) { 
          return tryMoveSelection(lm, 1); 
         } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) { 
          return tryMoveSelection(lm, -1); 
         } 
        } 
       } 
       else if(event.getAction() == KeyEvent.ACTION_UP && isConfirmButton(event) 
         && ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != KeyEvent.FLAG_LONG_PRESS)){ 
        mRecyclerView.findViewHolderForAdapterPosition(mSelectedItem).itemView.performClick(); 
        return true; 
       } 
       return false; 
      } 
     }); 
    } 

    private boolean tryMoveSelection(RecyclerView.LayoutManager lm, int direction) { 
     int nextSelectItem = mSelectedItem + direction; 

     // If still within valid bounds, move the selection, notify to redraw, and scroll 
     if (nextSelectItem >= 0 && nextSelectItem < getItemCount()) { 
      notifyItemChanged(mSelectedItem); 
      mSelectedItem = nextSelectItem; 
      notifyItemChanged(mSelectedItem); 
      //lm.scrollToPosition(mSelectedItem); 
      mRecyclerView.smoothScrollToPosition(mSelectedItem); 
      return true; 
     } 

     return false; 
    } 

    public Context getContext(){ return mContext; } 

    public int getSelectedItem() { return mSelectedItem; } 
    public void setSelectedItem(int selectedItem) { mSelectedItem = selectedItem; } 

    public RecyclerView getRecyclerView() { return mRecyclerView; } 


    @Override 
    public void onBindViewHolder(VH holder, int position) { 
     onBindViewHolder(holder, position); 
    } 

    public static boolean isConfirmButton(KeyEvent event){ 
     switch (event.getKeyCode()){ 
      case KeyEvent.KEYCODE_ENTER: 
      case KeyEvent.KEYCODE_DPAD_CENTER: 
      case KeyEvent.KEYCODE_BUTTON_A: 
       return true; 
      default: 
       return false; 
     } 
    } 


}