Adding proper keyboard support to RecyclerView

孤街浪徒 提交于 2020-12-01 09:24:22

问题


In one of my previous questions, I asked (and answered by myself following this blog post) how to properly handle key input on a RecyclerView.

Now I realized that if I keep an arrow key pressed, let's say down key, the scrolling downwards stops and the RecyclerView loses its focus, probably because the scrolling is faster than the generation of all the children Views.

Is there any workaround or better practice to properly handle hardware keyboard inputs on a RecyclerView?

Update:

I published a basic example here, it works flawlessly now, no more focus losses.


回答1:


I managed to implement an abstract Adapter class capable of keeping track of the selected item without losing item focus, a sample project can be found here, the specific implementation of the adapter class is below:

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


}


来源:https://stackoverflow.com/questions/37461532/adding-proper-keyboard-support-to-recyclerview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!