在TV上,用RecyclerView显示一个列表,飞鼠遥控左右遥控获得Item焦点,到最后一个举行右移动换行,是不能做到的,因此必要监听key事件处置惩罚换行。
结果图如下
代码实现
Item.xml布局
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="10dp"
- android:clickable="true"
- android:focusable="true"
- android:gravity="center"
- android:focusableInTouchMode="true"
- android:background="@drawable/focusable_view_bg"
- android:orientation="vertical">
- <ImageView
- android:id="@+id/img"
- android:layout_width="100dp"
- android:layout_height="100dp"
- android:src="@drawable/girl1"
- android:scaleType="fitXY" />
- <TextView
- android:id="@+id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="Test1" />
- </LinearLayout>
复制代码 focusable_view_bg.xml 获得焦点和悬浮
在drawable创建focusable_view_bg.xml
- <selector xmlns:android="http://schemas.android.com/apk/res/android">
- <!-- 悬浮 -->
- <item android:state_hovered="true">
- <shape>
- <corners android:radius="15dp" />
- <solid android:color="#66000000" />
- <stroke android:width="2dp" android:color="#fff000" />
- </shape>
- </item>
- <!-- 获得焦点 -->
- <item android:state_focused="true">
- <shape>
- <corners android:radius="15dp" />
- <stroke android:width="2dp" android:color="#fff000" />
- <solid android:color="#66000000" />
- </shape>
- </item>
- </selector>
复制代码 activity_main.xml布局
- <?xml version="1.0" encoding="utf-8"?>
- <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context=".MainActivity">
- <Button
- android:id="@+id/btn_move_left"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="左移动"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- <Button
- android:id="@+id/btn_move_right"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="右移动"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- <Button
- android:id="@+id/btn_enter"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="点击"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/recycler_list"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:focusable="true"
- android:clickable="true"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/btn_move_right" />
- </androidx.constraintlayout.widget.ConstraintLayout>
复制代码 Adapter类
- package com.dfg.recyclerviewfocus;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.view.KeyEvent;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ImageView;
- import android.widget.TextView;
- import androidx.annotation.NonNull;
- import androidx.recyclerview.widget.RecyclerView;
- import java.util.ArrayList;
- import java.util.Map;
- public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
- private Context context;
- private ArrayList<Map<String, Object>> list;
- private OnItemClickListener itemClickListener;
- private OnIconKeyListener iconKeyListener;
- public void setOnItemClickListener(OnItemClickListener itemClickListener) {
- this.itemClickListener = itemClickListener;
- }
- public void setOnIconKeyListener(OnIconKeyListener iconKeyListener) {
- this.iconKeyListener = iconKeyListener;
- }
- public MyAdapter(Context context, ArrayList<Map<String, Object>> list) {
- this.context = context;
- this.list = list;
- }
- static class ViewHolderItem extends RecyclerView.ViewHolder {
- ImageView imgAppPic;//app图片
- TextView tvAppName;// app 名字
- public ViewHolderItem(View view) {
- super(view);
- imgAppPic = view.findViewById(R.id.img);
- tvAppName = view.findViewById(R.id.title);
- }
- }
- @NonNull
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
- ViewHolderItem viewHolderItem = new ViewHolderItem(view);
- return viewHolderItem;
- }
- @Override
- public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
- ViewHolderItem holder = (ViewHolderItem) viewHolder;
- Map<String, Object> item = list.get(position);
- holder.imgAppPic.setImageBitmap((Bitmap) item.get("icon"));
- holder.tvAppName.setText(item.get("title").toString());
- holder.itemView.setOnClickListener(v -> {
- if (itemClickListener != null) {
- itemClickListener.itemClick(v, holder.getAdapterPosition());
- }
- });
- holder.itemView.setOnKeyListener(new View.OnKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- if(iconKeyListener!=null) {
- return iconKeyListener.onKey(v,keyCode,event,holder.getAdapterPosition());
- }
- return false;
- }
- });
- }
- @Override
- public int getItemCount() {
- return list.size();
- }
- // 点击 Item 回调
- interface OnItemClickListener {
- void itemClick(View view, int position);
- }
- // 回调Key
- interface OnIconKeyListener{
- boolean onKey(View v, int keyCode, KeyEvent event,int position);
- }
- }
复制代码 MainActivity
- public class MainActivity extends AppCompatActivity {
- private String TAG = "MainActivity";
- private Button btnMoveRight;
- private Button btnMoveLeft;
- private Button btnEnter;
- private RecyclerView recyclerView;
- private MyAdapter myAdapter;
- private ArrayList<Map<String, Object>> list = new ArrayList<>();
- // 列数,网格布局中每行4个Item
- private int numColumns = 4;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- init();
- setData();
- click();
- }
- public void init() {
- btnMoveRight = findViewById(R.id.btn_move_right);
- btnMoveLeft = findViewById(R.id.btn_move_left);
- btnEnter = findViewById(R.id.btn_enter);
- recyclerView = findViewById(R.id.recycler_list);
- }
- /**
- * 设置数据源并初始化RecyclerView
- */
- public void setData() {
- for (int i = 0; i < 30; i++) {
- Map map = new HashMap();
- map.put("icon", BitmapFactory.decodeResource(getResources(), R.drawable.girl1));
- map.put("title", "test" + i);
- list.add(map);
- }
- myAdapter = new MyAdapter(getApplicationContext(), list);
- GridLayoutManager gridLayoutManager = new GridLayoutManager(this, numColumns);
- recyclerView.setLayoutManager(gridLayoutManager);
- recyclerView.setAdapter(myAdapter);
- }
- public void click() {
- // 右移按钮点击事件
- btnMoveRight.setOnClickListener(v -> {
- try {
- // 查找当前获得焦点的视图
- View focusedView = recyclerView.findFocus();
- // 如果RecyclerView没有获得焦点
- if (focusedView != null) {
- // 获取RecyclerView的子类第0个item
- int position = recyclerView.getChildAdapterPosition(focusedView);
- Log.d(TAG, "当前获得焦点的Item位置: " + position);
- Runtime.getRuntime().exec("input keyevent 22");
- } else {
- Log.d(TAG, "没有任何Item获得焦点");
- if (recyclerView.getLayoutManager() != null) {
- // 如果没有获得焦点的视图,默认让第一个可见项获得焦点
- int firstPosition = ((GridLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
- View positionChild = recyclerView.getLayoutManager().findViewByPosition(firstPosition);
- if (positionChild != null) {
- positionChild.requestFocus();// 让第一个Item获得焦点
- }
- }
- }
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- });
- // 左移按钮点击事件
- btnMoveLeft.setOnClickListener(v -> {
- try {
- // 查找当前获得焦点的视图
- View focusedView = recyclerView.findFocus();
- // 如果RecyclerView没有获得焦点
- if (focusedView != null) {
- // 获取RecyclerView的子类第0个item
- int position = recyclerView.getChildAdapterPosition(focusedView);
- Log.d(TAG, "当前获得焦点的Item位置: " + position);
- } else {
- Log.d(TAG, "没有任何Item获得焦点");
- if (recyclerView.getLayoutManager() != null) {
- // 如果没有获得焦点的视图,默认让第一个可见项获得焦点
- int firstPosition = ((GridLayoutManager) recyclerView.getLayoutManager()).findFirstVisibleItemPosition();
- View positionChild = recyclerView.getLayoutManager().findViewByPosition(firstPosition);
- if (positionChild != null) {
- positionChild.requestFocus();// 让第一个Item获得焦点
- }
- }
- }
- Runtime.getRuntime().exec("input keyevent 21");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- });
- // 确认按钮点击事件
- btnEnter.setOnClickListener(v -> {
- try {
- Runtime.getRuntime().exec("input keyevent 66");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- });
- myAdapter.setOnItemClickListener(new MyAdapter.OnItemClickListener() {
- @Override
- public void itemClick(View view, int position) {
- Toast.makeText(getApplicationContext(), list.get(position).get("title").toString(), Toast.LENGTH_SHORT).show();
- }
- });
- // 设置RecyclerView Item键盘事件监听
- myAdapter.setOnIconKeyListener(new MyAdapter.OnIconKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event, int position) {
- // 获取按键动作类型
- final int action = event.getAction();
- // 检查按键是否为按下动作
- final boolean handleKeyEvent = (action != KeyEvent.ACTION_UP);
- // 标记按键是否被处理
- boolean wasHandled = false;
- switch (keyCode) {
- // 左键按下事件
- case KeyEvent.KEYCODE_DPAD_LEFT:
- // 不是手指抬起操作
- if (handleKeyEvent) {
- // 如果当前的 Item 是 LinearLayout
- if (v instanceof LinearLayout) {
- // 当前当前的 Item父类 是 RecyclerView
- if (v.getParent() instanceof RecyclerView) {
- // 如果当前项在一列最后一项 或 第0项
- if (position % numColumns == 0) {
- // position的位置一定要 >= 0,因为这里要进行换行了
- if (position - 1 >= 0) {
- if (recyclerView.getLayoutManager() != null) {
- // 这里进行位置 -1,如果是屏幕看不到上一行,就会为Null
- View positionChild = recyclerView.getLayoutManager().findViewByPosition(position - 1);
- if (positionChild != null) {
- // 将焦点移动到前一个Item
- positionChild.requestFocus();
- } else {
- // 如果当前屏幕看不到上一个Item时,这里就会为 null,然后上滑到前一项。
- // 平滑滚动到前一项
- recyclerView.smoothScrollToPosition(position - 1);
- try {
- // 再次执行左键按下
- Runtime.getRuntime().exec("input keyevent 21");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- wasHandled = true;
- }
- }
- }
- }
- }
- }
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- // 不是手指抬起操作
- if (handleKeyEvent) {
- // 如果当前的 Item 是 LinearLayout
- if (v instanceof LinearLayout) {
- // 当前当前的 Item父类 是 RecyclerView
- if (v.getParent() instanceof RecyclerView) {
- // 当前的位置+1 < adapter的item总数
- if (position + 1 < myAdapter.getItemCount()) {
- // 如果 当前位置+1 % 列数 =0,表示下一个是下一行了
- if ((position + 1) % numColumns == 0) {
- if (recyclerView.getLayoutManager() != null) {
- // 获取下一个item,如果是屏幕看不到下一行,就会为Null
- View positionChild = recyclerView.getLayoutManager().findViewByPosition(position + 1);
- if (positionChild != null) {
- // 将焦点移动到下一个Item
- positionChild.requestFocus();
- } else {
- // 如果当前屏幕看不到下一个Item时,这里就会为 null,然后下滑到前一项。
- // 平滑滚动到下一项
- recyclerView.smoothScrollToPosition(position + 1);
- try {
- Runtime.getRuntime().exec("input keyevent 22");
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- }
- // 返回true,事件自己消费处理了。
- wasHandled = true;
- }
- } else if (position + 1 == myAdapter.getItemCount()) {
- wasHandled = true;
- }
- }
- }
- }
- break;
- }
- return wasHandled;
- }
- });
- }
- }
复制代码 RecyclerView相关方法
- recyclerView.getLayoutManager().findViewByPosition(positon):获取当前显示的某个位置的子视图。
- recyclerView.getChildAdapterPosition(View):获取某个子视图在适配器中的位置。
- recyclerView.smoothScrollToPosition(positon):平滑滚动 RecyclerView 到指定位置。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |