RecyclerView焦點循環切換的方法
RecyclerView我們使用的很多了,做TV開發的時候,當焦點在第一項時按上鍵希望能跳到最後一項,焦點在最後一項時按下鍵跳到第一項,recyclerView沒有這個功能的,現在就介紹如何實現這個功能。
1,在recyclerView的adapter的onBindViewHolder裏對viewHolder設置按鍵監聽。
public class ManagerFavoritesRecycleViewAdapter extends RecyclerView.Adapter<ManagerFavoritesRecycleViewAdapter.ViewHolder> {
private OnRecycleViewItemSelectListener mOnItemSelectLister;
private OnRecycleViewItemClickListener mOnItemClickLister;
private OnRecyclerViewItemKeyListener mOnKeyListener;
private Context mContext;
private ArrayList<ManagerServiceEntity> mServiceList;
public class ViewHolder extends RecyclerView.ViewHolder {
private TextView mChannelIndex;
private TextView mChannelName;
private ImageView mChannelFavStatus;
public ViewHolder(View view) {
super(view);
mChannelIndex = (TextView) view.findViewById(R.id.tv_channel_index);
mChannelName = (TextView) view.findViewById(R.id.tv_channel_name);
mChannelFavStatus = (ImageView) view.findViewById(R.id.im_fav_status);
}
}
public ManagerFavoritesRecycleViewAdapter(Context context, ArrayList<ManagerServiceEntity> service_list) {
this.mContext = context;
this.mServiceList = service_list;
}
public void setOnItemSelectListener(OnRecycleViewItemSelectListener listener) {
mOnItemSelectLister = listener;
}
public void setOnItemClickLister(OnRecycleViewItemClickListener listener) {
mOnItemClickLister = listener;
}
public void setOnKeyListener(OnRecyclerViewItemKeyListener listener) {
mOnKeyListener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.manager_favorites_recycleview_holder, viewGroup, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int position) {
ManagerServiceEntity serviceInfoEntity = mServiceList.get(position);
viewHolder.mChannelIndex.setText(String.valueOf(serviceInfoEntity.getServiceLcn()));
viewHolder.mChannelName.setText(DVBPlayerUtil.filterSpecialChar(serviceInfoEntity.getServiceName()));
if (serviceInfoEntity.getServiceIndex() == 1) {
viewHolder.mChannelFavStatus.setBackgroundResource(R.drawable.icon_fave);
} else {
viewHolder.mChannelFavStatus.setBackgroundResource(R.drawable.translucent_background);
}
if(mOnItemSelectLister != null) {
viewHolder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View view, boolean hasFocus) {
mOnItemSelectLister.onItemSelected(view, position, hasFocus);
}
});
}
if (mOnItemClickLister != null) {
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mOnItemClickLister.onItemClick(view, position);
}
});
}
if (mOnKeyListener != null) {
viewHolder.itemView.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
return mOnKeyListener.recyclerViewItemOnKey(v, keyCode, event, position);
}
});
}
}
@Override
public int getItemCount() {
return this.mServiceList.size();
}
public ManagerServiceEntity getItemDataByPosition(int position) {
if (mServiceList != null && mServiceList.size() > 0) {
return mServiceList.get(position);
}
return null;
}
public ArrayList<ManagerServiceEntity> getServiceList() {
return mServiceList;
}
public void setServiceList(ArrayList<ManagerServiceEntity> service_list) {
this.mServiceList = service_list;
}
public interface OnRecycleViewItemSelectListener {
void onItemSelected(View view, int position, boolean hasFocus);
}
public interface OnRecycleViewItemClickListener {
void onItemClick(View view,int position);
}
public interface OnRecyclerViewItemKeyListener {
boolean recyclerViewItemOnKey(View view, int keyCode, KeyEvent event, int position);
}
}
2、監聽後的實現
private ManagerFavoritesRecycleViewAdapter mChannelAdapter;
mChannelAdapter = new ManagerFavoritesRecycleViewAdapter(getContext(), new ArrayList<ManagerServiceEntity>());
mChannelAdapter.setOnItemSelectListener(new OnRecycleViewItemSelectListener() {
private View mLastView = null;
@Override
public void onItemSelected(View view, int position, boolean hasFocus) {
ObjectAnimator animator1;
ObjectAnimator animator2;
//Log.d("wujiang", "mAdapter's onItemSelected");
if (mLastView != null && hasFocus == false) {
animator1 = ObjectAnimator.ofFloat(mLastView, "scaleX", 1.02f, 1f);
animator2 = ObjectAnimator.ofFloat(mLastView, "scaleY", 1.05f, 1f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(200);
animSet.playTogether(animator1, animator2);
animSet.start();
}
if (view != null && hasFocus == true) {
View scale_view = view.findViewById(R.id.ll_index_name);
animator1 = ObjectAnimator.ofFloat(scale_view, "scaleX", 1f, 1.02f);
animator2 = ObjectAnimator.ofFloat(scale_view, "scaleY", 1f, 1.05f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(200);
animSet.playTogether(animator1, animator2);
animSet.start();
mLastView = scale_view;
} else {
mLastView = null;
}
}
});
mChannelAdapter.setOnItemClickLister(new OnRecycleViewItemClickListener() {
@Override
public void onItemClick(View view, int position) {
}
});
mChannelAdapter.setOnKeyListener(new OnRecyclerViewItemKeyListener() {
@Override
public boolean recyclerViewItemOnKey(View view, int keyCode, KeyEvent event, int position) {
if (event.getAction() == KeyEvent.ACTION_UP) {
return false;
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_UP:
if (position == 0) {
mBtnSpace.requestFocus();
mUserChannelRecyclerView.scrollToPosition(mChannelAdapter.getItemCount() - 1);
mUserChannelRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
requestFocus(mUserChannelRecyclerView, mChannelAdapter.getItemCount() - 1);
}
}, 100);
return true;
}
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
int item_count = mUserChannelRecyclerView.getAdapter().getItemCount();
if (position == (item_count - 1) ) {
mBtnSpace.requestFocus();
mUserChannelRecyclerView.scrollToPosition(0);
mUserChannelRecyclerView.postDelayed(new Runnable() {
@Override
public void run() {
requestFocus(mUserChannelRecyclerView, 0);
}
}, 100);
return true;
}
default:
return true;
}
return false;
}
});
}
private void requestFocus(RecyclerView recyclerView, int position) {
View view = recyclerView.getChildAt(position);
LinearLayoutManager llM = (LinearLayoutManager) recyclerView.getLayoutManager();
if (view != null) {
view.requestFocus();
} else if (llM.findViewByPosition(position) != null) {
llM.findViewByPosition(position).requestFocus();
} else {
recyclerView.requestFocus();
}
}
重點看recyclerViewItemOnKey。先調用scrollToPosition滑到指定的位置,然後延時100MS調用requestFocus讓指定的view獲取焦點。
那mBtnSpace.requestFocus()是幹什麼用的呢?
如果沒有mBtnSpace.requestFocus(),當你用遙控器一下一下按的時候,焦點能正確的從第一項跳到最後一項,從最後一項跳到第一項。但是當你一直按着遙控器,跳到第一項或者最後一項後焦點就飛掉了(因爲我們的UI往往比較複雜)。
於是我就定義了一個很小的透明的Button,讓它先獲取焦點,這樣就能保證焦點不飛。只讓這個Button獲取焦點還不夠,要過濾掉所有的按鍵消息。
mBtnSpace.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
return true;
}
});
THE END