前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Android自定义View新年烟花、祝福语横幅动画

Android自定义View新年烟花、祝福语横幅动画

作者头像
砸漏
发布2020-11-03 11:15:57
8380
发布2020-11-03 11:15:57
举报
文章被收录于专栏:恩蓝脚本

新年了,项目中要作个动画,整体要求实现彩带乱飞,烟花冲天而起,烟花缩放,小鸡换图,小鸡飘移,横幅裁剪、展开等动画效果,全局大量使用了属性动画来实现。

如下效果图:

我在实现过程中,横幅的裁剪计算,捣腾了比较久的时间,初版采用属性动画计算float的一个比率值,来配合每一帧的裁剪绘制,如下代码:

代码语言:javascript
复制
private static class RollView extends View { 
private Bitmap mBitmap; 
private Rect mSrc; 
private Rect mDst; 
private int mRollWidth = 60; 
private float mRate; 
private boolean mIsStopAnim; 
public RollView(Context context) { 
super(context); 
mSrc = new Rect(); 
mDst = new Rect(); 
} 
@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
super.onMeasure(widthMeasureSpec, heightMeasureSpec); 
} 
@Override 
protected void onDraw(Canvas canvas) { 
if (mBitmap == null) return; 
drawFromMiddleByFloatCompute(canvas); 
} 
private void drawFromMiddleByFloatCompute(Canvas canvas) { 
/* 
以下src 都需要加上mBitmap. 的前缀,, 因从drawable拿到的是原始图片宽高 
而适配时,可能view的宽高比 drawable的宽高还小或大 
*/ 
final float rate = mRate; 
mSrc.left = 0; 
mSrc.top = 0; 
mSrc.right = mRollWidth; 
mSrc.bottom = mBitmap.getHeight(); 
mDst.left = (int) ((getWidth() / 2 - mRollWidth) - (getWidth() / 2 - mRollWidth) * rate); 
mDst.top = 0; 
mDst.right = mDst.left + mRollWidth + 1;//因精度问题,这里强制+1 
mDst.bottom = getHeight(); 
canvas.drawBitmap(mBitmap, mSrc, mDst, null); 
//中间 
int sw = (int) ((mBitmap.getWidth() - mRollWidth * 2) * rate); 
mSrc.left = mBitmap.getWidth() / 2 - sw / 2; 
mSrc.top = 0; 
mSrc.right = mSrc.left + sw; 
mSrc.bottom = mBitmap.getHeight(); 
int dw = (int) ((getWidth() - mRollWidth * 2) * rate); 
mDst.left = getWidth() / 2 - dw / 2; 
mDst.top = 0; 
mDst.right = mDst.left + dw; 
mDst.bottom = getHeight(); 
canvas.drawBitmap(mBitmap, mSrc, mDst, null); 
//右边 
mSrc.left = mBitmap.getWidth() - mRollWidth; 
mSrc.top = 0; 
mSrc.right = mBitmap.getWidth(); 
mSrc.bottom = mBitmap.getHeight(); 
mDst.left = (int) (getWidth() / 2 + (getWidth() / 2 - mRollWidth) * rate); 
mDst.top = 0; 
mDst.right = mDst.left + mRollWidth; 
mDst.bottom = getHeight(); 
canvas.drawBitmap(mBitmap, mSrc, mDst, null); 
} 
public void setRes(int resId) { 
mBitmap = getBitmapFromLocal(resId); 
} 
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB) 
public void startFloatComputeAnim() { 
/* 
如果有float获取比率值,从而计算出相应的坐标值,那么可能由于最终在转成Rect的坐标时, 
float to int ,有精度的损失:1个px 而引起效果的不理想 
*/ 
ValueAnimator animator = ValueAnimator.ofFloat(0, 1); 
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
@Override 
public void onAnimationUpdate(ValueAnimator animation) { 
if (mIsStopAnim) { 
animation.cancel(); 
return; 
} 
mRate = (float) animation.getAnimatedValue(); 
invalidate(); 
} 
}); 
animator.setDuration(2000); 
animator.start(); 
} 
public void stopAnim() { 
mIsStopAnim = true; 
} 
} 

因float转int有一个精度损失的问题,所以在计算中强制加上了1px(代码中有); 这样虽然解决了有1px没有绘制的问题,但是会发生绘制时不够平滑,而出现抖动的情形(在某些devices上) 所以最好还是不要使用float来计算 后来,同事猜想使用一个固定int值 来参与计算,可能可以解决上述问题: 比如每秒30帧,这里动画时长2秒,即共30*2=60帧; 图片宽度、左画轴、右画轴 对 60帧数 做相应的除法及其他计算,可得出一个单帧中 它们应该运动的x距离 之后,我又想了一种,使用一个属性动画,来计算出从0到getWidth()之间的 动画值, 从而通过计算,使得横幅从左向右拉开, 如下:

代码就不整体开源了

以上就是本文的全部内容,希望对大家的学习有所帮助。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-09-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档