ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android TV 焦点控制实例

2020-08-06 12:32:07  阅读:303  来源: 互联网

标签:TV public int 实例 import Android view android View


首先上实例:

项目工程文件:

 

 

 

 

界面布局:

activity_tab.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:background="@color/fastlane_background"
    android:orientation="vertical"
    tools:context=".activity.TabActivity">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv_tan"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:descendantFocusability="afterDescendants"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintLeft_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="4"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/main_img"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:background="@drawable/bg_recyclerview_item"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:padding="15dp"
            android:src="@drawable/pro2"



            />

       <!-- <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/main_tab_rv"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"/>-->


        <com.example.focusdome.view.FocusRecyclerView
            android:id="@+id/main_tab_rv"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"

            />


    </LinearLayout>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1">

    <androidx.recyclerview.widget.RecyclerView

        android:id="@+id/button_tab_rv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"


        />
    </LinearLayout>

</LinearLayout>

layout_found_h_recycler_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:orientation="vertical"
    android:focusable="true"
    android:background="@drawable/bg_recyclerview_item"
    android:padding="20dp"
    >

    <com.example.focusdome.view.CircleImageView
        android:id="@+id/f_h_c_img"
        android:layout_width="109dp"
        android:layout_height="0dp"
        android:layout_gravity="center"
        android:layout_weight="3"

        android:src="@drawable/pro5"


        />


    <TextView
        android:id="@+id/f_h_c_txt"
        android:layout_width="120dp"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center"
        android:text="1111"
        android:textSize="10dp"
        />





</LinearLayout>

layout_main_recycler_txtrecycler.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:focusable="true"
    android:background="@drawable/bg_recyclerview_item"
    >

    <TextView
        android:id="@+id/main_rv_rv_txt"
        android:layout_width="match_parent"
        android:layout_height="60dp"


        android:gravity="center"
        />


</LinearLayout>

layout_recycler_text_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:layout_gravity="center"
    android:orientation="horizontal"
    android:gravity="center"
    android:background="@drawable/bg_recyclerview_item"
    android:focusable="true">


    <TextView
        android:id="@+id/tv"
        android:layout_width="120dp"
        android:layout_height="60dp"
        android:textColor="#ffffff"
        android:textSize="16sp"
        android:text=""
        android:padding="10dp"
        android:gravity="center"
        />

</LinearLayout>

资源文件:

bg_recyclerview_item.xml

 

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:drawable="@drawable/bg_recyclerview_focus" android:state_selected="true" />
    <item android:drawable="@drawable/bg_recyclerview_focus" android:state_focused="true" />
    <item android:drawable="@drawable/bg_recyclerview_focus" android:state_pressed="true" />
    <item android:drawable="@color/transparent"/>
</selector>

bg_recyclerview_focus.xml:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#80B469FF" />
            <corners android:radius="10dp" />
        </shape>
    </item>
    <item android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#60B469FF" />
            <corners android:radius="8dp" />
        </shape>
    </item>
    <item
        android:bottom="5dp"
        android:left="5dp"
        android:right="5dp"
        android:top="5dp">
        <shape
            android:layout_width="wrap_content"
            android:shape="rectangle">
            <stroke
                android:width="1dp"
                android:color="#6672f8" />
        </shape>
    </item>
    <item
        android:bottom="6dp"
        android:left="6dp"
        android:right="6dp"
        android:top="6dp">
        <shape android:shape="rectangle">
            <stroke
                android:width="1dp"
                android:color="#6672f8" />
        </shape>
    </item>

    <item
        android:bottom="7dp"
        android:left="7dp"
        android:right="7dp"
        android:top="7dp">
        <color android:color="@color/color_141843"/>
    </item>
</layer-list>

activity代码:

package com.example.focusdome.activity;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
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 android.widget.Toast;

import com.example.focusdome.R;
import com.example.focusdome.adapter.BtnRecyclerViewAdapter;
import com.example.focusdome.adapter.MainRecyclerViewAdapter;
import com.example.focusdome.adapter.MyRecyclerViewAdapter;
import com.example.focusdome.model.RecyclerMainModel;
import com.example.focusdome.view.FocusLinearLayoutManager;
import com.example.focusdome.view.SpaceDecoration;

import java.util.ArrayList;

public class TabActivity extends Activity implements MyRecyclerViewAdapter.OnItemClickListener,MyRecyclerViewAdapter.OnItemFocusChangeListener{

    private MyRecyclerViewAdapter adapter;
    private RecyclerView recyclerView;
    private String[] titles = {"首页", "游戏","教育","生活","娱乐","新闻","直播","我的"};

    private ImageView imageView;


    //主体部分
    private MainRecyclerViewAdapter mAdapter;
    private RecyclerView mainRecyclerView;

    private ArrayList<RecyclerMainModel> list = new ArrayList<>();



   //底部部分
    private BtnRecyclerViewAdapter btnRecyclerViewAdapter;
    private RecyclerView btnRecyclerView;




    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab);
        initView();
        initAdapter();

        //初始化主体部分recycle
        mainRecyclerView = findViewById(R.id.main_tab_rv);

        list.add(new RecyclerMainModel("第一张",R.drawable.pre));
        list.add(new RecyclerMainModel("第二张",R.drawable.pro));
        list.add(new RecyclerMainModel("第三张",R.drawable.pro2));
        list.add(new RecyclerMainModel("第四张",R.drawable.pro3));
        list.add(new RecyclerMainModel("第五张",R.drawable.pro4));
        list.add(new RecyclerMainModel("第六张",R.drawable.hp_one));
        list.add(new RecyclerMainModel("第七张",R.drawable.hp_four));
        list.add(new RecyclerMainModel("第八张",R.drawable.hp_five));


        mAdapter = new MainRecyclerViewAdapter(this, list, new MainRecyclerViewAdapter.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                Log.v("点击:", "" + position + view.getId());

                imageView.setImageResource(list.get(position).getM_imgId());
                //imageView.setScaleType(ImageView.ScaleType.CENTER);


            }
        }/*, new MainRecyclerViewAdapter.OnItemFocusChangeListener() {
            @Override
            public void onItemFocusChange(View view, int position, boolean hasFocus) {


               // Toast.makeText(TabActivity.this,"focus"+position,Toast.LENGTH_LONG).show();

                imageView.setImageResource(list.get(position).getM_imgId());


            }
        }*/) {

            //获得焦点时处理
            @Override
            protected void onItemFocus(View itemView,int positon) {
               imageView.setImageResource(list.get(positon).getM_imgId());

               System.out.println("获取焦点成功!"+positon);
                Log.i("view:",itemView.getId()+"23333");
                itemView.setSelected(true);
                View view = itemView.findViewById(R.id.main_rv_rv_txt);

                view.setSelected(true);


            }
            //失去焦点时

            @Override
            protected void onItemGetNormal(View itemView) {
                System.out.println("失去焦点成功!");
                Log.i("view:",itemView.getId()+"32222");
               itemView.setSelected(false);
                View view = itemView.findViewById(R.id.main_rv_rv_txt);
                view.setSelected(true);


            }
        };
        FocusLinearLayoutManager linearLayoutManager = new FocusLinearLayoutManager(this,LinearLayoutManager.VERTICAL,false);
        mainRecyclerView.setLayoutManager(linearLayoutManager);
        mainRecyclerView.addItemDecoration(new SpaceDecoration(30));
        mainRecyclerView.setAdapter(mAdapter);



        //初始化底部部分
        btnRecyclerView = (RecyclerView)findViewById(R.id.button_tab_rv);
        btnRecyclerViewAdapter = new BtnRecyclerViewAdapter(this, list) {
            @Override
            protected void onItemFocus(View itemView, int position) {
                itemView.setSelected(true);
                //View view = itemView.
            }

            @Override
            protected void onItemGetNormal(View itemView) {
                   itemView.setSelected(false);
            }
        };

        FocusLinearLayoutManager linearLayoutManager1 = new FocusLinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);

        btnRecyclerView.setLayoutManager(linearLayoutManager1);
        btnRecyclerView.setAdapter(btnRecyclerViewAdapter);




    }







    private void initView() {
        recyclerView = findViewById(R.id.rv_tan);
        imageView= findViewById(R.id.main_img);


        imageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean b) {
                Log.v("img_focus",""+view.getId());
            }
        });

    }

    private void initAdapter() {
        adapter = new MyRecyclerViewAdapter(this, titles);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(adapter);
        recyclerView.requestFocus();
        adapter.setmOnItemClickListener(this);
        adapter.setmOnItemClickListener(this);
    }

    @Override
    public void onItemClick(View view, int position) {
        Log.i("Activity:onItemClick","mOnItemFocusChangeListener.onItemFocusChange(v, position, hasFocus);");
    }

    @Override
    public void onItemFocusChange(View view, int position, boolean hasFocus) {



    }


    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        


        return super.onKeyDown(keyCode, event);
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        //View v =  getCurrentFocus();




        return super.dispatchKeyEvent(event);



    }
}

adapter代码:

其余的adapter基本和这个差不多

package com.example.focusdome.adapter;

import android.content.Context;
import android.os.Build;
import android.util.Log;
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.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.example.focusdome.R;
import com.example.focusdome.activity.TabActivity;
import com.example.focusdome.model.RecyclerMainModel;

import java.util.ArrayList;

public abstract class BtnRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;

    private ArrayList<RecyclerMainModel> data;

    private MyRecyclerViewAdapter.OnItemFocusChangeListener mOnItemFocusChangeListener;

    private MyRecyclerViewAdapter.OnItemClickListener mOnItemClickListener;

    private final LayoutInflater layoutInflater;
    private int defaultFocus = 0;
    private boolean needFocus = true;


    public BtnRecyclerViewAdapter(Context context, ArrayList<RecyclerMainModel> list) {
        this.context = context;
        this.data = list;
        layoutInflater = LayoutInflater.from(context);
    }

    public interface OnItemClickListener{
        void onItemClick(View view, int position);

    }


    public interface OnItemFocusChangeListener{
        void onItemFocusChange(View view, int position, boolean hasFocus);

    }

    public final void setmOnItemClickListener(@Nullable MyRecyclerViewAdapter.OnItemClickListener listener){
        mOnItemClickListener = listener;
    }

    private void setmOnItemFocusChangeListener(@Nullable MyRecyclerViewAdapter.OnItemFocusChangeListener focusChangeListener){
        this.mOnItemFocusChangeListener = focusChangeListener;
    }



    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = layoutInflater.inflate(R.layout.layout_found_h_recycler_item,parent,false);


        return  new RecyclerViewHolder(v);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder,final int position) {
        RecyclerViewHolder viewHolder = (RecyclerViewHolder)holder;

        viewHolder.imageView.setImageResource(data.get(position).getM_imgId());
        viewHolder.textView.setText(data.get(position).getM_txt());

        if (mOnItemClickListener != null) {
            holder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mOnItemClickListener.onItemClick(v, position);
                    Log.e("click事件:","你点击了"+v.getId());
                }
            });
        }


            holder.itemView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
                @Override
                public void onFocusChange(View v, boolean hasFocus) {
                  if (hasFocus){
                      focusStatus(v,position);


                  }else {

                      normalStatus(v);

                  }

                    Log.i("adapter:","onFocusChange");
                }
            });




        if (needFocus) {
            Log.i("进行移动:",":");

            if (defaultFocus < 0) {

                defaultFocus = 0;
            }
            if (defaultFocus >= getItemCount()) {
                defaultFocus = getItemCount() - 1;
            }
            if (defaultFocus == position) {
                if (!holder.itemView.isFocusable()) {
                    defaultFocus++;
                } else {
                    holder.itemView.requestFocus();
                }
            }
        } else {
            //setNeedFocus(position == (getItemCount() - 1));
        }

    }

    @Override
    public int getItemCount() {
        return data.size();
    }





    private class RecyclerViewHolder extends RecyclerView.ViewHolder {

        public TextView textView;

        public ImageView imageView;


        public RecyclerViewHolder(@NonNull View itemView) {
            super(itemView);

            textView = (TextView) itemView.findViewById(R.id.f_h_c_txt);

            imageView = (ImageView)itemView.findViewById(R.id.f_h_c_img);


        }
    }

    /**
     * item获得焦点时调用
     *
     * @param itemView view
     */
    private void focusStatus(View itemView,int position) {
        if (itemView == null) {
            return;
        }


        float scalX,scalY;
        scalX = 1.1f;
        scalY = 1.1f;
        if (Build.VERSION.SDK_INT >= 21) {
            //抬高Z轴
            ViewCompat.animate(itemView).scaleX(scalX).scaleY(scalY).translationZ(1.3f).start();
        } else {
            ViewCompat.animate(itemView).scaleX(scalX).scaleY(scalY).start();
            ViewGroup parent = (ViewGroup) itemView.getParent();
            parent.requestLayout();
            parent.invalidate();
        }
        onItemFocus(itemView,position);
    }

    /**
     * 当item获得焦点时处理
     *
     * @param itemView itemView
     */
    protected abstract void onItemFocus(View itemView,int position);

    /**
     * item失去焦点时
     *
     * @param itemView item对应的View
     */
    private void normalStatus(View itemView) {
        if (itemView == null) {
            return;
        }
        if (Build.VERSION.SDK_INT >= 21) {
            ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).translationZ(0).start();
        } else {
            ViewCompat.animate(itemView).scaleX(1.0f).scaleY(1.0f).start();
            ViewGroup parent = (ViewGroup) itemView.getParent();
            parent.requestLayout();
            parent.invalidate();
        }
        onItemGetNormal(itemView);
    }

    /**
     * 当条目失去焦点时调用
     *
     * @param itemView 条目对应的View
     */
    protected abstract void onItemGetNormal(View itemView);


}

model代码:

package com.example.focusdome.model;

public class RecyclerMainModel {
    private String m_txt;
    private int m_imgId;

    public RecyclerMainModel(String m_txt, int m_imgId) {
        this.m_txt = m_txt;
        this.m_imgId = m_imgId;
    }

    public String getM_txt() {
        return m_txt;
    }

    public void setM_txt(String m_txt) {
        this.m_txt = m_txt;
    }

    public int getM_imgId() {
        return m_imgId;
    }

    public void setM_imgId(int m_imgId) {
        this.m_imgId = m_imgId;
    }
}

view代码:

CircleImageView.java:

自定义圆形ImageView

package com.example.focusdome.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;

@SuppressLint("AppCompatCustomView")
public class CircleImageView extends ImageView { //画笔
    private Paint mPaint;
    //圆形图片的半径
    private int mRadius;
    //图片的宿放比例
    private float mScale;

    public CircleImageView(Context context) {
        super(context);
    }

    public CircleImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public CircleImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //由于是圆形,宽高应保持一致
        int size = Math.min(getMeasuredWidth(), getMeasuredHeight());
        mRadius = size / 2;
        setMeasuredDimension(size, size);
    }

    @SuppressLint("DrawAllocation")
    @Override
    protected void onDraw(Canvas canvas) {

        mPaint = new Paint();
        mPaint.setColor(Color.WHITE);

        Drawable drawable = getDrawable();

        if (null != drawable) {
            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();

            //初始化BitmapShader,传入bitmap对象
            BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            //计算缩放比例
            mScale = (mRadius * 2.0f) / Math.min(bitmap.getHeight(), bitmap.getWidth());

            Matrix matrix = new Matrix();
            matrix.setScale(mScale, mScale);
            bitmapShader.setLocalMatrix(matrix);
            mPaint.setShader(bitmapShader);
            //画圆形,指定好坐标,半径,画笔
            canvas.drawCircle(mRadius, mRadius, mRadius, mPaint);
        } else {
            super.onDraw(canvas);
        }
    }





}

自定义RecyclerView,重写dispatchKeyEvent()方法,进行焦点控制:

FocusRecyclerView:

package com.example.focusdome.view;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;

public class FocusRecyclerView extends RecyclerView {
    public FocusRecyclerView(@NonNull Context context) {
        super(context);
    }

    public FocusRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public FocusRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }


    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            int keyCode = event.getKeyCode();

            //水平垂直的时候:按下左键或者右键
            if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT /*|| keyCode == KeyEvent.KEYCODE_DPAD_DOWN || keyCode == KeyEvent.KEYCODE_DPAD_UP*/) {

                //获取当前焦点的视图
                View focusedView = getFocusedChild();
                View nextFocusView;
                try {

                   /* switch (keyCode){
                        case KeyEvent.KEYCODE_DPAD_LEFT:
                            Log.v("left","往左");
                            //通过findNextFocus获取下一个需要的焦点的vie
                            nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_LEFT);
                            break;

                        case KeyEvent.KEYCODE_DPAD_RIGHT:
                            Log.v("right","往右");
                            nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_RIGHT);
                            break;

                        case KeyEvent.KEYCODE_DPAD_UP:
                            Log.v("up","往上");
                            nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_UP);
                            break;

                        case KeyEvent.KEYCODE_DPAD_DOWN:
                            nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView,View.FOCUS_DOWN);

                            Log.v("down","往下");
                            break;
                        default:
                            nextFocusView = null;
                            break;


                    }*/


                    if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {

                        Log.v("left", "焦点往左跑");
                        //通过findNextFocus获取下一个需要得到的焦点的view
                        nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_LEFT);
                        if(nextFocusView == null){
                            Log.v("同级","View查找");
                          //  nextFocusView = FocusFinder.getInstance().findNextFocus(this,focusedView.getRootView().,View.FOCUS_LEFT);
                             nextFocusView = focusedView.getParent().focusSearch(focusedView,View.FOCUS_LEFT);

                        }

                    } else {
                        Log.v("right", "右边跑");
                        //通过findNextFocus获取下一个需要得到的焦点的View
                        nextFocusView = FocusFinder.getInstance().findNextFocus(this, focusedView, View.FOCUS_RIGHT);
                    }


                } catch (Exception e) {

                    nextFocusView = null;
                }
                //如果获取失败,消耗掉事件,不让系统处理,并让原先的view获取焦点
                if (nextFocusView == null) {


                    focusedView.requestFocus();
                    return true;
                }

            }


        }


        return super.dispatchKeyEvent(event);
    }


    @Override
    public View focusSearch(int direction) {


        return super.focusSearch(direction);
    }
}

SpaceDecoration.java

package com.example.focusdome.view;

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.View;

import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.OrientationHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import com.chad.library.adapter.base.BaseQuickAdapter;

import static android.widget.LinearLayout.VERTICAL;

public class SpaceDecoration extends RecyclerView.ItemDecoration {

    private int space;
    private int headerCount = -1;
    private int footerCount = Integer.MAX_VALUE;
    private boolean mPaddingEdgeSide = true;
    private boolean mPaddingStart = true;
    private boolean mPaddingHeaderFooter = false;
    private ColorDrawable mColorDrawable;

    private boolean mDrawLastItem = true;
    private boolean mDrawHeaderFooter = false;


    public SpaceDecoration(int space) {
        this.mColorDrawable = new ColorDrawable(Color.parseColor("#e7e7e7"));
        this.space = space;
    }

    public SpaceDecoration(int space, int color) {
        this.mColorDrawable = new ColorDrawable(color);
        this.space = space;
    }

    public void setPaddingEdgeSide(boolean mPaddingEdgeSide) {
        this.mPaddingEdgeSide = mPaddingEdgeSide;
    }

    public void setPaddingStart(boolean mPaddingStart) {
        this.mPaddingStart = mPaddingStart;
    }

    public void setPaddingHeaderFooter(boolean mPaddingHeaderFooter) {
        this.mPaddingHeaderFooter = mPaddingHeaderFooter;
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        int position = parent.getChildAdapterPosition(view);
        int spanCount = 0;
        int orientation = 0;
        int spanIndex = 0;
        int headerCount = 0, footerCount = 0;
        if (parent.getAdapter() instanceof BaseQuickAdapter) {
            headerCount = ((BaseQuickAdapter) parent.getAdapter()).getHeaderLayoutCount();
            footerCount = ((BaseQuickAdapter) parent.getAdapter()).getFooterLayoutCount();
        }

        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof StaggeredGridLayoutManager) {
            orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
            spanCount = ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
            spanIndex = ((StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
        } else if (layoutManager instanceof GridLayoutManager) {
            orientation = ((GridLayoutManager) layoutManager).getOrientation();
            spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
            spanIndex = ((GridLayoutManager.LayoutParams) view.getLayoutParams()).getSpanIndex();
        } else if (layoutManager instanceof LinearLayoutManager) {
            orientation = ((LinearLayoutManager) layoutManager).getOrientation();
            spanCount = 1;
            spanIndex = 0;
        }

        /**
         * 普通Item的尺寸
         */
        if ((position >= headerCount && position < parent.getAdapter().getItemCount() - footerCount)) {

            if (orientation == VERTICAL) {
                float expectedWidth = (float) (parent.getWidth() - space * (spanCount + (mPaddingEdgeSide ? 1 : -1))) / spanCount;
                float originWidth = (float) parent.getWidth() / spanCount;
                float expectedX = (mPaddingEdgeSide ? space : 0) + (expectedWidth + space) * spanIndex;
                float originX = originWidth * spanIndex;
                outRect.left = (int) (expectedX - originX);
                outRect.right = (int) (originWidth - outRect.left - expectedWidth);
                if (position - headerCount < spanCount && mPaddingStart) {
                    outRect.top = space;
                }
                outRect.bottom = space;
                return;
            } else {
                float expectedHeight = (float) (parent.getHeight() - space * (spanCount + (mPaddingEdgeSide ? 1 : -1))) / spanCount;
                float originHeight = (float) parent.getHeight() / spanCount;
                float expectedY = (mPaddingEdgeSide ? space : 0) + (expectedHeight + space) * spanIndex;
                float originY = originHeight * spanIndex;
                outRect.bottom = (int) (expectedY - originY);
                outRect.top = (int) (originHeight - outRect.bottom - expectedHeight);
                if (position - headerCount < spanCount && mPaddingStart) {
                    outRect.left = space;
                }
                outRect.right = space;
                return;
            }
        } else if (mPaddingHeaderFooter) {
            if (orientation == VERTICAL) {
                outRect.right = outRect.left = mPaddingEdgeSide ? space : 0;
                outRect.top = mPaddingStart ? space : 0;
            } else {
                outRect.top = outRect.bottom = mPaddingEdgeSide ? space : 0;
                outRect.left = mPaddingStart ? space : 0;
            }
        }

    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {

        if (parent.getAdapter() == null) {
            return;
        }

        int orientation = 0;
        int headerCount = 0, footerCount = 0, dataCount;

        if (parent.getAdapter() instanceof BaseQuickAdapter) {
            headerCount = ((BaseQuickAdapter) parent.getAdapter()).getHeaderLayoutCount();
            footerCount = ((BaseQuickAdapter) parent.getAdapter()).getFooterLayoutCount();
            dataCount = parent.getAdapter().getItemCount();
        } else {
            dataCount = parent.getAdapter().getItemCount();
        }
        int dataStartPosition = headerCount;
        int dataEndPosition = headerCount + dataCount;


        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        if (layoutManager instanceof StaggeredGridLayoutManager) {
            orientation = ((StaggeredGridLayoutManager) layoutManager).getOrientation();
        } else if (layoutManager instanceof GridLayoutManager) {
            orientation = ((GridLayoutManager) layoutManager).getOrientation();
        } else if (layoutManager instanceof LinearLayoutManager) {
            orientation = ((LinearLayoutManager) layoutManager).getOrientation();
        }
        int start, end;
        if (orientation == OrientationHelper.VERTICAL) {
            start = parent.getPaddingLeft();
            end = parent.getWidth() - parent.getPaddingRight();
        } else {
            start = parent.getPaddingTop();
            end = parent.getHeight() - parent.getPaddingBottom();
        }

        int childCount = parent.getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = parent.getChildAt(i);
            int position = parent.getChildAdapterPosition(child);

            if (position >= dataStartPosition && position < dataEndPosition - 1//数据项除了最后一项
                    || (position == dataEndPosition - 1 && mDrawLastItem)//数据项最后一项
                    || (!(position >= dataStartPosition && position < dataEndPosition) && mDrawHeaderFooter)//header&footer且可绘制
                    ) {

                if (orientation == OrientationHelper.VERTICAL) {
                    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                    int top = child.getBottom() + params.bottomMargin;
                    int bottom = top;
                    mColorDrawable.setBounds(start, top, end, bottom);
                    mColorDrawable.draw(c);
                } else {
                    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
                    int left = child.getRight() + params.rightMargin;
                    int right = left;
                    mColorDrawable.setBounds(left, start, right, end);
                    mColorDrawable.draw(c);
                }
            }
        }
    }
}

防止按键速度过快RecyclerView焦点乱飞问题:

FocusLinearLayoutManager.java

package com.example.focusdome.view;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;

public class FocusLinearLayoutManager extends LinearLayoutManager {
    public FocusLinearLayoutManager(Context context) {
        super(context);
    }

    public FocusLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
        super(context, orientation, reverseLayout);
    }

    public FocusLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }


    @Nullable
    @Override
    public View onInterceptFocusSearch(@NonNull View focused, int direction) {

        Log.v("manger","ssssss");

        int currentPosition = getPosition(getFocusedChild());
        int count = getItemCount();
        int lastVisiblePosition = findLastVisibleItemPosition();

        switch (direction){
            case View.FOCUS_RIGHT:
                currentPosition++;
                break;
            case View.FOCUS_LEFT:
                currentPosition++;
                break;
            case View.FOCUS_DOWN:
                currentPosition++;
                break;
            case View.FOCUS_UP:
                currentPosition++;
                break;

        }

        if (currentPosition<0||currentPosition>count){
            return focused;
        }else {
            if (currentPosition>lastVisiblePosition){
                scrollToPosition(currentPosition);
            }

        }



        return super.onInterceptFocusSearch(focused, direction);
    }
}

 项目地址:https://download.csdn.net/download/qq_41861266/12691503

标签:TV,public,int,实例,import,Android,view,android,View
来源: https://www.cnblogs.com/123-sxs/p/13445254.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有