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次演化,虽然可能还有问题,但是基本的需求已经满足,也慢慢走上了代码封装之路,不是以前的那种遇到问题就害怕,也不去思考其他解决方法,病急乱投医的那种状态了,而是去思考为啥会出现这样的问题?有没有其他方案?能不能不用第三方自己去封装解决?学会了自己思考解决问题.当然这不是最好的方案,还有很多更好的,只是当初项目很着急上线根据实际情况进行了修改,当然这里只是写出本文记录一下当初的心路历程.