2016-05-26 37 views
12

前のquestionsの1つで、RecyclerViewのキー入力を適切に処理する方法を質問しました(そして、自分自身でthisブログ記事に回答しました)。RecyclerViewへの適切なキーボードサポートの追加

は、今私は私が押された矢印キーを続けるならば、のキーダウン言わせていることを実現し、下方向にスクロールが停止し、RecyclerViewはスクロールがすべての子どもView秒の世代よりも高速であるためか、そのフォーカスを失いました。

RecyclerViewのハードウェアキーボード入力を適切に処理するための回避策がありますか?

更新:

私は基本的な例hereを発表し、それはより多くの損失を集中し、今完璧に動作しません。

+2

ドゥあなたは[mcve]を持っていますか?私は昨日あなたがそれをやっていた行に沿って、 'RecyclerView'にキーボードサポートを追加していました。私の場合、それはフルスクリーンのRecyclerViewですので、私は焦点の問題はありませんでした。問題の具体的な実装があれば、人々があなたが問題を過ぎ去るのを手助けする方が簡単になります。 – CommonsWare

+0

@CommonsWare私は自分の例をできるだけ早く作成します。 RecyclerViewの下にフォーカス可能なビュー(ボタンなど)を追加し、100個のアイテムのアダプタで大規模なデータセットを使用することをお勧めします。あなたは奇妙な動作を見なければなりません。 – Vektor88

+0

明日これを突きつけます。私は他の奇妙な結果(例えば、塗りつけ効果)を見ていました。私たちはおそらく、最初のイベントがキーイベントごとに処理されるのではなく、処理が完了するまで、 'RecyclerView'を2度目に更新するのを待つ必要があると思います。すべてのことが言われている、垂直方向のスクロールリストの下でフォーカス可能なビューを持っていることは、最初の良いキーボードUXではありません。 Android TV(またはGoogle TVの前身、Fire TVなど)用のアプリの作成については、そのようなことについての議論が表示されます。 – CommonsWare

答えて

4

私はアイテムのフォーカスを失うことなく、選択した項目のトラックを保つことができる抽象アダプタクラスを実装するために管理し、サンプルプロジェクトがhereを見つけることができ、アダプタクラスの具体的な実装は以下の通りです:

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


} 
関連する問題