AndroidTV开发View焦点放大缩小的封装演化之路

AndroidTV开发View焦点放大缩小的封装演化之路

前言:

TV开发中常见的View处于焦点状态时放大缩小带边框效果,这一篇博客将讲解为啥要封装?如何封装焦点状态放大缩小工具类以及封装的演化之路。

1.为啥要封装:

首先我们看之前的代码:

scss 复制代码
@Override
public void onFocusChange(final View v, boolean hasFocus) {
    //初始化放大倍数
    float scaleX1, scaleX2, scaleY1, scaleY2;
    scaleX1 = scaleY1 = scaleX2 = scaleY2 = scale0;
    //给获取焦点的view设置倍数
    if (v.getId() == R.id.iv_my_recent || v.getId() == R.id.iv_my_collect) {
        scaleX2 = scaleY2 = scaleL;
    }
    if (v.getId() == R.id.iv_my_handle || v.getId() == R.id.iv_my_remote || v.getId() == R.id.iv_my_qrcode) {
        scaleX2 = scaleY2 = scaleS;
    }
    //获得焦点时的状态和倍数
    if (hasFocus) {
        lastFocus = v;
        //在android5.0以上的效果
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            v.animate()
                    .scaleXBy(scaleX1)
                    .scaleX(scaleX2)
                    .scaleYBy(scaleY1)
                    .scaleY(scaleY2)
                    .zBy(z1)
                    .z(z2)
                    .setDuration(animateDuration);
        } else {
            //在android5.0以下的效果
            v.animate()
                    .scaleXBy(scaleX1)
                    .scaleX(scaleX2)
                    .scaleYBy(scaleY1)
                    .scaleY(scaleY2)
                    .withEndAction(new Runnable() {
                        @Override
                        public void run() {
                            //防止view被遮挡
                            v.bringToFront();
                        }
                    })
                    .setDuration(animateDuration);
        }
    } else {
        //view在焦点消失后的倍数和状态
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            v.animate()
                    .scaleXBy(scaleX2)
                    .scaleX(scaleX1)
                    .scaleYBy(scaleY2)
                    .scaleY(scaleY1)
                    .zBy(z2)
                    .z(z1)
                    .setDuration(animateDuration);
        } else {
            v.animate()
                    .scaleXBy(scaleX2)
                    .scaleX(scaleX1)
                    .scaleYBy(scaleY2)
                    .scaleY(scaleY1)
                    .setDuration(animateDuration);
        }
    }
}
​
​
​

2.封装原因分析:

可以看到上面的代码可以实现多个view的焦点放大缩小效果,但是如果一个界面有多个类型的列表和复杂的布局的话,需要根据view写很多if判断,这样的话代码重复率很多,耦合太高,甚至会有成千上万行代码,找view也不好找, 这样很不友好,而且如果其他界面也有很多view的话又要写一遍这个代码,是不是感觉很啰嗦,完全不符合好的代码规范,于是我产生了一个封装通用工具类的概念,但是又不能影响现有功能和进度,方便后面的开发。

3.初步封装如下:

4.完整代码如下:

scss 复制代码
/**
 * @author: njb
 * @date: 2020/10/11 0011 23:56
 * @desc:
 */
public class FocusViewUtils {
    private static final float scale0 = 1f;
    private static final float scaleL = 1.1f;
    private static final float scaleS = 1.13f;
    private static final float z1 = 0f;
    private static final float z2 = 1f;
    private static final long animateDuration = 20;
    private static View lastFocus;
​
    /**
     * view获取焦点时放大/缩小
     *
     * @param v
     */
    public static void scaleView(View v) {
        v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(final View v, boolean hasFocus) {
                //初始化放大倍数
                float scaleX1, scaleX2, scaleY1, scaleY2;
                scaleX1 = scaleY1 = scaleX2 = scaleY2 = scale0;
                //给获取焦点的view设置倍数
                if (v.getId() == R.id.iv_my_recent || v.getId() == R.id.iv_my_collect) {
                    scaleX2 = scaleY2 = scaleL;
                }
                if (v.getId() == R.id.iv_my_handle || v.getId() == R.id.iv_my_remote || v.getId() == R.id.iv_my_qrcode) {
                    scaleX2 = scaleY2 = scaleS;
                }
                //获得焦点时的状态和倍数
                if (hasFocus) {
                    lastFocus = v;
                    //在android5.0以上的效果
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        v.animate()
                                .scaleXBy(scaleX1)
                                .scaleX(scaleX2)
                                .scaleYBy(scaleY1)
                                .scaleY(scaleY2)
                                .zBy(z1)
                                .z(z2)
                                .setDuration(animateDuration);
                    } else {
                        //在android5.0以下的效果
                        v.animate()
                                .scaleXBy(scaleX1)
                                .scaleX(scaleX2)
                                .scaleYBy(scaleY1)
                                .scaleY(scaleY2)
                                .withEndAction(new Runnable() {
                                    @Override
                                    public void run() {
                                        //防止view被遮挡
                                        v.bringToFront();
                                    }
                                })
                                .setDuration(animateDuration);
                    }
                } else {
                    //view在焦点消失后的倍数和状态
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        v.animate()
                                .scaleXBy(scaleX2)
                                .scaleX(scaleX1)
                                .scaleYBy(scaleY2)
                                .scaleY(scaleY1)
                                .zBy(z2)
                                .z(z1)
                                .setDuration(animateDuration);
                    } else {
                        v.animate()
                                .scaleXBy(scaleX2)
                                .scaleX(scaleX1)
                                .scaleYBy(scaleY2)
                                .scaleY(scaleY1)
                                .setDuration(animateDuration);
                    }
                }
            }
        });
    }
}
​

5.封装后的使用:

可以看出很简单,调用FocusViewUtils.scaleView()方法,只需要传递需要放大缩小的view即可,接入成本很低,但是放大view的方法里面还是有之前的问题,只是这里不需要每个界面都写一遍放大缩小的方法,而是传递view,这里的初步封装就完成了.

6.第二次封装:

在前面的基础之上进一步封装,达到简化代码的效果: 之前的封装是传入相应的view,但是每次使用的时候很不方便,于是进行了第二次封装,添加一个type参数,不在需要传入view,传入相应的缩放比例类型即可很方便。

7.FocusViewUtils工具类代码如下:

scss 复制代码
public class FocusViewUtils {
    private static final float scale0 = 1f;
    private static final float scaleL = 1.1f;
    private static final float scaleS = 1.13f;
    private static final float z1 = 0f;
    private static final float z2 = 1f;
    private static final long animateDuration = 20;
    private static View lastFocus;
​
    /**
     * view获取焦点时放大/缩小
     * @param v     焦点view
     * @param type 焦点状态view放大的类型
     */
    public static void scaleView(View v, final int type) {
        v.setOnFocusChangeListener(new View.OnFocusChangeListener() {
            @Override
            public void onFocusChange(final View v, boolean hasFocus) {
                //初始化放大倍数
                float scaleX1, scaleX2, scaleY1, scaleY2;
                scaleX1 = scaleY1 = scaleX2 = scaleY2 = scale0;
                if (type == 0) {
                    scaleX2 = scaleY2 = scaleL;
                }
                if (type == 1) {
                    scaleX2 = scaleY2 = scaleS;
                }
                //获得焦点时的状态和倍数
                if (hasFocus) {
                    lastFocus = v;
                    //在android5.0以上的效果
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        v.animate()
                                .scaleXBy(scaleX1)
                                .scaleX(scaleX2)
                                .scaleYBy(scaleY1)
                                .scaleY(scaleY2)
                                .zBy(z1)
                                .z(z2)
                                .setDuration(animateDuration);
                    } else {
                        //在android5.0以下的效果
                        v.animate()
                                .scaleXBy(scaleX1)
                                .scaleX(scaleX2)
                                .scaleYBy(scaleY1)
                                .scaleY(scaleY2)
                                .withEndAction(new Runnable() {
                                    @Override
                                    public void run() {
                                        //防止view被遮挡
                                        v.bringToFront();
                                    }
                                })
                                .setDuration(animateDuration);
                    }
                } else {
                    //view在焦点消失后的倍数和状态
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                        v.animate()
                                .scaleXBy(scaleX2)
                                .scaleX(scaleX1)
                                .scaleYBy(scaleY2)
                                .scaleY(scaleY1)
                                .zBy(z2)
                                .z(z1)
                                .setDuration(animateDuration);
                    } else {
                        v.animate()
                                .scaleXBy(scaleX2)
                                .scaleX(scaleX1)
                                .scaleYBy(scaleY2)
                                .scaleY(scaleY1)
                                .setDuration(animateDuration);
                    }
                }
            }
        });
    }
}

8.演化分析:

上面的代码就是通过设置一个type,判断如果type为0放大倍数为1.1f,type为1时放大倍数为1.13f,当然这里只是示例,小伙伴们可以根据自己的项目进行设置相对应的倍数.这样的话只需要传入一个焦点view和type即可,不需要像之前一样还需要判断传入的view是啥,然后设置放大倍数,这样的话更方便,少了很多判断和重复代码,更符合代码封装的原则.

9.在项目的实际使用如下:

10.最后的效果图如下:

11.总结:

以上就是我的焦点view放大缩小工具类的封装演化之路,在不影响现有功能和开发进度的情况下进行了2次演化,虽然可能还有问题,但是基本的需求已经满足,也慢慢走上了代码封装之路,不是以前的那种遇到问题就害怕,也不去思考其他解决方法,病急乱投医的那种状态了,而是去思考为啥会出现这样的问题?有没有其他方案?能不能不用第三方自己去封装解决?学会了自己思考解决问题.当然这不是最好的方案,还有很多更好的,只是当初项目很着急上线根据实际情况进行了修改,当然这里只是写出本文记录一下当初的心路历程.

12.项目的源码如下:

TvRecyclerView: TV项目,使用recyclerview实现标题切换和焦点效果

相关推荐
夏非夏21 分钟前
Android 生成并加载PDF文件
android
B.-2 小时前
在 Flutter 应用中调用后端接口的方法
android·flutter·http·ios·https
夏非夏2 小时前
Kotlin jetpack MVP
android·kotlin
️ 邪神2 小时前
【Android、IOS、Flutter、鸿蒙、ReactNative 】约束布局
android·flutter·ios·鸿蒙·reactnative
ch_kexin2 小时前
Android kotlin integer-array 存放图片资源ID
android·开发语言·kotlin
steptoward2 小时前
MacOS编译hello_xr——记一次CMake搜索路径限制导致的ANDROID_NATIVE_APP_GLUE not found
android·macos·xr
七月.末5 小时前
安卓aab包的安装教程,附带adb环境的配置
android·adb
SRC_BLUE_1710 小时前
SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based
android·网络安全·adb·less
无尽的大道13 小时前
Android打包流程图
android
镭封14 小时前
android studio 配置过程
android·ide·android studio