android 焦点框绘制,android自定义View(三)——动画焦点框

闲话

本来最近在做一个IPTV的广告插件包,因为这个项目没多少功能,仅仅涉及悬浮Window的相关操作,所以后面就很闲,看到别的同事在分析阿狸TV市场的一个炫酷效果,所以就索性自己尝试仿效一下。

模仿效果

这个炫酷的效果大致如下:1.当视图容器里的子视图发生焦点切换时,一个悬浮的焦点框(不是系统的)会从失去焦点的子视图上飘移到获得焦点的子视图上,并且焦点框的大小逐渐变化为获得焦点视图的大小;2,飘移完成后,获得焦点的子视图放大、焦点框放大,失去焦点的子视图缩小。可能我描述起来大家觉得很抽象,有兴趣的童鞋可以去到自家电视上找找(估计没多少机顶盒有阿狸市场),或者运行我的demo,看看基础效果。

过程分析

这里先说明,由于我不是专门负责这个效果的,所以我实现第一个效果后就没有往下继续了,后续效果由别的同事研究,所以以下内容仅围绕第一种效果展开。

估计大部分童鞋都会想到,要实现这个效果,使用的东西要么是动画,要么是矩阵。不错,我是用矩阵也实现了,但是矩阵出现的问题是.9的边框放大后直接画出来也会失真,所以我采用动画。但是可能大部分童鞋都和我一样只是常使用View Animation,我本来也想使用View Animation,但是发现控制焦点框宽高均匀动态变化好难(网上有教使用缩放&平移动画混合并计算动画偏移的方法可以实现这个效果,不过我智商太低,真的看不懂O(∩_∩)O),主要问题在于AnimationListener里没有动画实时更新回调的相关接口,所以我只好另寻出路,于是乎,我认识了Property Animation。关于Property Animation,有兴趣的童鞋请移步:PropertyAnimation详解。

实施过程

1.一个自定义ViewGroup

这个容器的作用主要作用是控制焦点框的初始位置和大小以及对子视图焦点变化事件的捕获。

/** * com.ykbjson.view.MFocusView * *@author Kebin.Yan *@Description 子view获得焦点时焦点框有动画效果的视图容器 *@date Create At :2015年7月2日 上午9:01:37 */

public class MFocusView extends RelativeLayout implements OnFocusChangeListener, OnClickListener {

private final String TAG = getClass().getSimpleName();

/** * 焦点框 */

private FloatView floatView;

/** * 是否初始化过 */

private boolean isInit;

public MFocusView(Context context) {

this(context, null);

}

public MFocusView(Context context, AttributeSet attr) {

this(context, attr, 0);

}

public MFocusView(Context context, AttributeSet attr, int style) {

super(context, attr, style);

}

/** * 初始化焦点框 */

private void initFloatView()

{

int firstChildwidth = -1;

int firstChildHeight = -1;

//这个地方或许是不对的,因为不一定是第一个视图有焦点

View child = findFocus();

if(null==child)

getChildAt(0);

if (null != child) {

firstChildwidth = (int) (child.getRight() - child.getLeft());

firstChildHeight = (int) (child.getBottom() - child.getTop());

}

floatView = new FloatView(getContext());

LayoutParams floatParams = new LayoutParams(firstChildwidth, firstChildHeight);

floatView.setId(4);

floatView.setLayoutParams(floatParams);

floatView.setFocusable(false);

floatView.setFocusableInTouchMode(false);

floatView.setScaleType(ScaleType.FIT_XY);

floatView.setImageResource(R.drawable.focus_bound);

addView(floatView);

if (null != child)

floatView.onReLayout(child.getLeft(), child.getTop(), firstChildwidth, firstChildHeight);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

super.onLayout(changed, l, t, r, b);

if (changed && !isInit) {

isInit = !isInit;

if (getChildCount() > 0) {

Log.e(TAG, "onLayout,childCount : " + getChildCount());

for (int i = 0; i < getChildCount(); i++) {

//加这个是为了在手机上测试

getChildAt(i).setOnClickListener(this);

//捕获子视图焦点

getChildAt(i).setOnFocusChangeListener(this);

}

}

initFloatView();

}

}

@Override

public void onClick(View child) {

onChildChange(child);

}

@Override

public void onFocusChange(View child, boolean hasFocus) {

Log.e(TAG, "onFocusChanged,hasFocus : " + hasFocus);

if (!hasFocus)

return;

onChildChange(child);

}

/** * 焦点框视图改变 */

private void onChildChange() {

View child = findFocus();

onChildChange(child);

}

/** * 焦点框视图改变 * *@param child 当前右焦有的视图 */

private void onChildChange(View child) {

if (null == child)

return;

float focusX = child.getLeft();

float focusY = child.getTop();

float focusW = child.getRight() - focusX;

float focusH = child.getBottom() - focusY;

floatView.onReLayout(focusX, focusY, focusW, focusH);

Log.e(TAG, "onChildChange,child : " + child);

}

}

这个类很简单,就是默认装载焦点框视图到最顶层,捕获到焦点变化后通知焦点框重绘和播放动画。

2.一个ImageView

/** * com.ykbjson.view.FloatView * *@author Kebin.Yan *@Description 焦点框视图 *@date Create At :2015年7月2日 上午9:02:14 */

public class FloatView extends ImageView {

private final String TAG = getClass().getSimpleName();

/** * x轴缩放率 */

private float scalX = 1.0f;

/** * y轴缩放率 */

private float scalY = 1.0f;

/** * 上一次view的x坐标 */

public float nFocusX;

/** * 上一次view的y坐标 */

public float nFocusY;

/** * 上一次view的宽度 */

public int nFocusW;

/** * 上一次view的高度 */

public int nFocusH;

public FloatView(Context context) {

super(context);

}

/** * 改变当前视图位置和大小 * *@param focusX 新的x坐标 *@param focusY 新的y坐标 *@param focusW 新的宽度 *@param focusH 新的高度 */

public void onReLayout(final float focusX, final float focusY, final float focusW, final float focusH) {

scalX = focusW / getWidth();

scalY = focusH / getHeight();

ValueAnimator valueAnimator = new ValueAnimator();

valueAnimator.setObjectValues(new LayoutParams(nFocusW, nFocusH));

valueAnimator.setInterpolator(new LinearInterpolator());

valueAnimator.setEvaluator(new TypeEvaluator() {

@Override

public LayoutParams evaluate(float fraction, LayoutParams startValue, LayoutParams endValue) {

Log.e(TAG, "evaluate , fraction = " + fraction);

LayoutParams params = new LayoutParams(0, 0);

params.width = (int) ((focusW - getWidth()) * fraction);

params.height = (int) ((focusH - getHeight()) * fraction);

return params;

}

});

valueAnimator.addUpdateListener(new AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

LayoutParams nParams = (LayoutParams) animation.getAnimatedValue();

LayoutParams params = (LayoutParams) getLayoutParams();

params.width += nParams.width;

params.height += nParams.height;

setLayoutParams(params);

}

});

valueAnimator.setStartDelay(250);

AnimatorSet set = new AnimatorSet();

set.playTogether(ObjectAnimator.ofFloat(this, "translationX", nFocusX, focusX), ObjectAnimator.ofFloat(this, "translationY", nFocusY, focusY), valueAnimator);

set.setDuration(500);

set.setTarget(this);

set.start();

nFocusX = focusX;

nFocusY = focusY;

nFocusW = (int) focusW;

nFocusH = (int) focusH;

}

@Override

protected void onDraw(Canvas canvas) {

Log.e(TAG, "onDraw " + " scalX : " + scalX + " scalY : " + scalY + " nFocusX : " + nFocusX + " nFocusY : " + nFocusY);

super.onDraw(canvas);

}

}

这个ImageView主要是实现焦点框(它本身)的平移和缩放,需要看的地方就是AnimatorUpdateListener那里,我就不再赘述了。

结语

存在的bug:

1.在多点触控手机上同时按两个按钮时动画混乱。

2.如果子视图不自定义selector,点击时系统原生的焦点框会先于这个飘移框出现

其实每次写文章不是为了贴代码,是希望弄清楚一些原理,更希望提升自己的语言组织能力和表达能力。

我相信,肯定有数不尽的大牛有很多的实现方式,但我依然要写出来,因为我希望让更多还未成为大牛的人得到一个思路。在浩瀚的Android攻城狮队伍中,我不过如那银河里的一粒星辰,即使渺小,但依然努力发光。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值