问题
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 View
s.
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