千家信息网

Android怎么实现吹蜡烛动画

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要介绍"Android怎么实现吹蜡烛动画"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"Android怎么实现吹蜡烛动画"文章能帮助大家解决问题。一、
千家信息网最后更新 2026年11月03日Android怎么实现吹蜡烛动画

这篇文章主要介绍"Android怎么实现吹蜡烛动画"的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇"Android怎么实现吹蜡烛动画"文章能帮助大家解决问题。

一、简介

我们来看这两根萌萌的小蜡烛。

小蜡烛憋足气把火焰燃起,一下被旁边的哥们吹灭了 0^0 ,看起来还是萌气十足的啊。看着图大家应该能想到应该怎么实现了吧,自定义View!对了,但是具体要怎么把这个过程做好呢,跟着脚步一起来看一看吧。代码稍微有点多,大家耐心观看,有兴趣的同学可以从我的GITHUB上clone下来,对着代码看。

二、过程实现

蜡烛的绘制和动画

  • 本着面向对象的思想,很明显这里就是两个蜡烛嘛!既然是这样那我们就定义一个蜡烛类具有蜡烛的基本属性。

public abstract class ICandle {       //蜡烛底部左下坐标      protected int mCurX;      protected int mCurY;      //蜡烛宽高      protected int mCandleWidth;      protected int mCandleHeight;      //蜡烛左眼坐标      protected Point mEyeLPoint;      //蜡烛右眼坐标      protected Point mEyeRPoint;      //蜡烛眼睛半径      protected int mEyeRadius;      //眼睛间隔距离      protected int mEyeDevide;      //身体颜色      protected int mCandleColor;      //是否停止动画中      protected boolean mIsAnimStoping = false;      //蜡烛芯坐标      protected Point mCandlewickPoint;      public void initAnim(){      }      public void stopAnim(){      }      public void drawSelf(Canvas canvas){      }  }

对应着这蜡烛还有代码,那就一目了然了。可能需要解释的应该就是下面的几个方法了public void initAnim(), stopAnim()初始化开始和结束动画需要的数据,小蜡烛将会实现这个方法,drawSelf(Canvas canvas)把画布传进来然后蜡烛自己绘制自己。

现在就是让我们来看一看小蜡烛身体内部构造的时候了,hiahiahiahia!

不对,和蜡烛生死相随的还有火焰呢!先来看看火焰吧,等下小蜡烛还要燃烧自己呢。+10086s

Flame

  • 一样先来一睹我们的富勒姆真容

好像也没什么毛病,首先是里面的区域,就是Flame啦,外面的呢,就是Flame先生燃烧自己散发的人性之光和飘散的骨灰(手动抹眼泪)。

来看一下Flame的实现吧。我们一步步分析。

private static float CHANGE_FACTOR = 20;     private Paint mPaint;     private Path mPath;     //左下点坐标     private int mCurX;     private int mCurY;     //火焰宽度     private int mWidth;     //火焰高度     private int mHeight;     //记录初始高度     private int mPreHeight;     //记录初始宽度     private int mPreWidth;     //火焰顶部贝塞尔曲线控制点变化参数     private int mTopXFactor;     private int mTopYFactor;     //用于实现火焰的抖动     private Random mRandom;     //光环半径     private int mHaloRadius;     //正在燃烧     private boolean mIsFiring;     //是否启动停止动画     private boolean mIsStopAnim = false;     private boolean mFlagStop = false;     private LinearGradient mLinearGradient;     private RadialGradient mRadialGradient;     private ValueAnimator mFlameAnimator;     private ValueAnimator mHaloAnimator;

参数就是这些了,主要是我们的动画实现过程,也就是我们的属性动画ValueAnimator这里还有两个渲染类不知道大家用过没有,LinearGradient和RadialGradient不了解的同学可以直接点我的博文了解一下。LinearGradient绘制出了火焰,RadialGradient绘制除了发散的光芒。

初始化的过程我就不写了,大家对这代码看吧。那主要的就是小火焰的是怎么绘制出来的呢 show the code

mPaint.setStyle(Paint.Style.FILL);     mPaint.setShader(mLinearGradient);     mPath.reset();     mPath.moveTo(mCurX, mCurY);     mPath.quadTo(mCurX + mWidth / 2,             mCurY + mHeight / 3,             mCurX + mWidth, mCurY);     mPath.quadTo(mCurX + mWidth / 2 + ((1 - mRandom.nextFloat()) * CHANGE_FACTOR) + mTopXFactor,             mCurY - 2 * mHeight + mTopYFactor,             mCurX, mCurY);     canvas.drawPath(mPath, mPaint);

这就是火焰flame的绘制,可以看到这里用到了二次贝塞尔曲线的绘制,不太清楚贝塞尔曲线的同学也可以点这波浪Loading动画(贝塞尔曲线)有简单的介绍,当时是用在一个水波的view里面。这里的绘制是以前面那个图里面的矩形为参照,我们再来看一下这个图(当然是加强版hiahia)。

那为什么上面的x坐标还加了mRandom.nextFloat()) * CHANGE_FACTOR呢?你想啊,火焰不是会左右晃动吗,利用一个随机来控制左右摆动咯。

mFlameAnimator = ValueAnimator.ofFloat(0, 4).setDuration(4000);     mFlameAnimator.setRepeatCount(ValueAnimator.INFINITE);     mFlameAnimator.addUpdateListener(                    new ValueAnimator.AnimatorUpdateListener() {         @Override         public void onAnimationUpdate(ValueAnimator animation) {             float zeroToOne = (float) animation.getAnimatedValue();             if (zeroToOne >= 1.0f && zeroToOne <= 1.2f) {                 //火焰燃起                 zeroToOne = 1.0f - 5 * (zeroToOne - 1.0f);//1-0                 mHeight = (int) (mPreHeight * (1 - zeroToOne));                 mIsFiring = true;             } else if (zeroToOne >= 3.5f) {                 if (mFlagStop) {                     mFlameAnimator.cancel();                     return;                 }                 //火焰被吹灭                 zeroToOne = 2 * (zeroToOne - 3.5f);//0-2                 mTopXFactor = (int) (-20 * zeroToOne);                 mTopYFactor = (int) (160 * zeroToOne);  /                    mWidth = (int) (mPreWidth * (1 -zeroToOne));                 mIsFiring = false;             }         }     });

在4秒的时间内,火焰进行了一系列活动,从下面随着灯芯移上来,不断的改变火焰的位置,分为了两部分,火焰燃起和火焰熄灭,从代码中可以看到,火焰燃起时mHeight慢慢变大,然后就是有了升起的过程辣,另外一个就是火焰被吹灭的时候,因为吹灭的时候火焰的高度肯定是保持之前的值,所以不需要改变,而是用了mTopXFactor和mTopYFactor这个两个因子来控制火焰的位置。好了,既然火焰有了,蜡炬成灰泪始干啊,生命之光也该出场了。

光圈的绘制和动画就相对简单了

mPaint.setStyle(Paint.Style.STROKE);             mPaint.setStrokeWidth(5);             mPaint.setShader(mRadialGradient);             canvas.drawCircle(mCurX + mWidth / 2,                          mCurY - mHeight / 2, mHaloRadius, mPaint);             canvas.drawCircle(mCurX + mWidth / 2,                          mCurY - mHeight / 2, mHaloRadius + 5, mPaint);             canvas.drawCircle(mCurX + mWidth / 2,                          mCurY - mHeight / 2, mHaloRadius - 5, mPaint);

这里改变的只有一个参数,mHaloRadius也就是光圈的半径。但是不要忘了,其他参数同时也是在改变的呢,只不过是放在了mFlameAnimator里面。

好了介绍到这Flame的介绍完了,任重而道远啊,写了这么多却还没完结,让我想到一某位古人说过,不是我。

还未老死,就先累死

  • FireCandle

这名字有点奇怪,火烛,厉害了Word哥。前面已经介绍过ICandle了,现在来看一下他的实现类,蜡烛两兄弟之FireCandle。

初始化照例也就不说了,来看该有的变量。

private Paint mPaint;  //中心X坐标  private int mCenterX;  //记录初始宽  private int mPreWidth;  //记录初始高  private int mPreHeight;  //蜡烛芯旋转角  private int mCandlewickDegrees = 0;  private Flame mFlame;  private boolean mIsFire = false;  private boolean mIsStateOnStart = false;  private boolean mIsStateOnEnd = false;  private boolean mFlagStop = false;  private ValueAnimator mCandlesAnimator;

命名还是挺规范的,应该一看就知道是干嘛的。

我们还是来主要看绘制和属性动画的配合,绘制就不看了(光速打脸)。来看动画。

mCandlesAnimator = ValueAnimator.ofFloat(0, 4).setDuration(4000);   mCandlesAnimator.addUpdateListener(                    new ValueAnimator.AnimatorUpdateListener() {       @Override       public void onAnimationUpdate(ValueAnimator animation) {           float zeroToOne = (float) animation.getAnimatedValue();           if (zeroToOne <= 1.0f) {               //蜡烛芯蓄力下拉               mIsFire = true;               mCandleWidth = mPreWidth + (int) (zeroToOne * 40);               mCandleHeight = mPreHeight - (int) (zeroToOne * 30);               mCandlewickDegrees = (int) (-60 + (180 + 60) * zeroToOne);               refreshEyePosition();           } else if (zeroToOne <= 2.0f) {               zeroToOne = zeroToOne - 1.0f;               //蜡烛芯上摆               if (zeroToOne <= 0.2f) {                   zeroToOne = 1.0f - 5 * zeroToOne;                   mIsFire = false;                   mCandleWidth = mPreWidth + (int) (zeroToOne * 40);                   mCandleHeight = mPreHeight - (int) (zeroToOne * 30);                   mCandlewickDegrees = (int) (180 * zeroToOne);               } else {                   if (mFlameStateListener != null && !mIsStateOnStart) {                       mFlameStateListener.flameStart();                       mIsStateOnStart = true;                   }                   mCandleWidth = mPreWidth;                   mCandleHeight = mPreHeight;                   mCandlewickDegrees = 0;                   if (mFlagStop) {                       mCandlesAnimator.cancel();                   }               }               refreshEyePosition();           } else if (zeroToOne >= 3.5f) {               //蜡烛芯被吹歪               zeroToOne = 2 * (zeroToOne - 3.5f);//0-1               mCandlewickDegrees = (int) (-60 * zeroToOne);               if (mFlameStateListener != null && !mIsStateOnEnd) {                   mFlameStateListener.flameEnd();                   mIsStateOnEnd = true;               }           }       }   });

这个就过程就有点多了,但是其实一点都不复杂,,首先我们看动画里面的小蜡烛,一开始,他来了一个变胖红脸深蹲,所以呢mCandleWidth是变大的,mCandleHeight是变小的,后面那个灯芯随着深蹲来了一个大角度旋转,灯芯的如何旋转大家也看到了,改变坐标系然后就可以了。用到了

canvas.rotate(mCandlewickDegrees, mCenterX, mCurY - mCandleHeight);这个方法。上摆过程也是一样的,就不多说了。refreshEyePosition();这个方法是改变眼睛位置的,两个地方都用到了所以稍微独立出来了。注意mIsFire这个变量,没有火焰的时候就做其他绘制,比如说红眼睛等等。好了好了,介绍到这,小蜡烛的部分就结束了。

SecCandle

大蜡烛,帅蜡烛镇楼,实际的绘制和小蜡烛的就差不多了,这里就不解释了。

共同绘制View和控制器

AnimControler

这个类的功能很简单,绘制地板部分还有就是把计算后传过来的高度宽度赋给两支蜡烛,然后控制两支蜡烛各自开始动画。

mFirCandle = new FirCandle(mRelativeX + mWidth / 6, mRelativeY + mHeight);   mFirCandle.initCandle(mFirCandleWidth, mFirCandleHeight);   mFirCandle.initAnim();   mSecCandle = new SecCandle(mRelativeX + mWidth / 2, mRelativeY + mHeight);   mSecCandle.initCandle(mSecCandleWidth, mSecCandleHeight - 80);   mSecCandle.initAnim();

***的***,就是我们的View了

  • CandlesAnimView

//16ms刷新Canvas       mInvalidateAnimator = ValueAnimator.ofInt(0, 1).setDuration(16);       mInvalidateAnimator.setRepeatCount(ValueAnimator.INFINITE);       mInvalidateAnimator.addListener(new AnimatorListenerAdapter() {           @Override           public void onAnimationRepeat(Animator animation) {               invalidate();           }       });       mInvalidateAnimator.start();

这个属性动画履行的任务就是快速的刷新界面,是Candle的动画能够及时显示。

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {      super.onMeasure(widthMeasureSpec, heightMeasureSpec);      int width = measureDimension(WIDTH_DEFAULT * mDensity,                                widthMeasureSpec);      int height = measureDimension(HEIGHT_DEFAULT *mDensity,                                heightMeasureSpec);     setMeasuredDimension(width, height); }  public int measureDimension(int defaultSize, int measureSpec) {      int result;      int specMode = MeasureSpec.getMode(measureSpec);      int specSize = MeasureSpec.getSize(measureSpec);      if (specMode == MeasureSpec.EXACTLY) {         result = specSize;     } else {         result = defaultSize;          if (specMode == MeasureSpec.AT_MOST) {             result = Math.min(result, specSize);         }     }      return result; }  @Override protected void onDraw(Canvas canvas) {      if (!mIsInit) {         initConfig();         mIsInit = true;     }     mAnimControler.drawMyView(canvas); }

可以看到***在view里面调用了我们的控制器,把cavas传过去了。

***的tip:大家有没有发现每个动画的duration都是一样的。

关于"Android怎么实现吹蜡烛动画"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注行业资讯频道,小编每天都会为大家更新不同的知识点。

蜡烛 火焰 动画 就是 坐标 过程 控制 代码 方法 两个 参数 属性 时候 曲线 高度 贝塞 贝塞尔 位置 半径 同学 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技有限公司 中关村互联网科技集团 疫情对互联网科技公司影响 互联网科技公司发展 杭州互联网科技公司 互联网科技上市公司 金融科技和互联网金融 深圳互联网科技怎么样 海南科技产业互联网平台 团飞科技与伯堂互联网服务平台 互联网与医疗科技 广西互联网科技孵化中心 恒生互联网科技业指数调整周期 美国互联网科技实力 广州千川互联网科技有限公司 有人说阿里系是互联网科技企业 上海乐五互联网科技有限公司 容联科技互联网电商 华人运通互联网科技公司 恒生科技互联网指数十大成分股 互联网与未来科技 万达互联网科技 美国互联网前沿科技 博兴的互联网电子科技公司 昭通云南众福互联网科技有限公司 金融科技与互联网金融相同和不同 互联网5g黑科技有哪些 注册互联网科技公司经营范围大全 广州梦谷互联网科技有限公司领导 互联网金融运营模式中的金融科技
0