Android 使用ObjectAnimator自定义动画

使用ObjectAnimator做一个自定义动画  动画效果大致类似水波纹的效果  先看图  没有GIF图 直接上静态图了

三个圈   内圈不变  外面两个圈变大缩小
每隔一会会出现一个小点  小点效果就是一个水波纹效果  并且出现的位置随机

 看完效果图 开始码代码  首先理一下思路   做这个效果需要解决的几个问题

1.外层两个圆圈扩大的时候的不会超出屏幕宽度

2.不定时出现的水波纹效果的出现区域应该在最外层圆圈没有放大时的区域

3.使用两个ObjectAnimator 分别控制圆圈的扩大和缩小,和水波纹效果的出现

还是直接先上代码

这个自定义view继承与View  然后重写draw()方法 看代码 


初始化
实现在canvas上画图
管理动画播放,暂停  以及移除


首先初始化各种值  初始化了三个圆圈的初始半径  和颜色  以及控制圆圈和OBjectAnimator和水波纹的颜色以及控制水波纹的ObjectAnimator   先说一下圆圈的大小收缩是利用scale实现的  然后水波纹的效果是利用颜色的渐变去实现圆圈的颜色透明度 以及圆圈的半径不断扩大 这个说波纹的效果就出来了

长话短说,主要讲具体实现的地方  

    在初始化这个自定义控件后干了一件事   重写View 的onSizeChanged()方法,在这里面去测量了控件的宽度 然后 宽度/10 就是最内圈圆的大小,接着第二个圆圈就在内圈的基础上加了一个值    外圈的半径又加一个更大的值 就确定下来了

然后就是使用ObjectAnimator去不断改变圆圈的属性  然后draw 就可以了     使用了ObjectAnimator.ofFloat();   查api可以知道   用我用的这个方法构造   

mCircleAnimator = ObjectAnimator.ofFloat(null, new FloatProperty() {

          @Override

          public void setValue(Object object, float value) {

                     mIsStartAnim = true;

                     mCircleWidth = value;

                     invalidate();

       }

}, 1.0f, 1.6f);

                 mCircleAnimator.setDuration(3000);

                  mCircleAnimator.setRepeatMode(ValueAnimator.REVERSE);

                 mCircleAnimator.setRepeatCount(ValueAnimator.INFINITE);

                 mCircleAnimator.start();

首先讲一下 FloatProperty() 这个对象  这个不是API提供的  这里我使用了一个动画库  compile"com.andkulikov:transitionseverywhere:1.7.0"

把圆圈缩放的比例,写在第三,第四个参数 然后在FloatProperty中重写的setValue() 就可以实时的取到这个动画从1.0-1.6的变化过程中的具体的变化值  这个变化的值就记为圆圈大小变化的倍数  这个在画圆的时候用以圆圈的半径乘上这个系数就可以得到一个新的圆圈的半径  然后在这个方法中调用View的invalidate();方法去不断重新的在画布上画圆就可以了

// 画内圈圆

initPaint(mInsideColor,10,255,Paint.Style.STROKE);

canvas.drawCircle(getWidth() /2,getHeight() /2,mStartInsideTrackWidth,mPaint);

floatbigWidth =mCircleWidth*mStartBigWidth;

if(bigWidth *2<= getWidth()) {

initPaint(mBigColor,1,255,Paint.Style.STROKE);

canvas.drawCircle(getWidth() /2,getHeight() /2,bigWidth,mPaint);

initPaint(mSmallColor,4,255,Paint.Style.STROKE);

canvas.drawCircle(getWidth() /2,getHeight() /2,mCircleWidth*mStartSmallWidth,mPaint);

以上就是画圆时的具体做法就是不断通过系数的改变去改变每一次画的圆的半径就行了,并且每次画新的圆之前都初始化一次画笔这样画笔的颜色就改变了

接着画水波纹

mWaterX=mRandom.nextInt(mStartBigWidth*2) +mSpaceWidth;

mWaterY=mRandom.nextInt(mStartBigWidth*2) +mSpaceWidth;

mWaterAnimator= ObjectAnimator.ofFloat(null, newFloatProperty() {

@Override

public voidsetValue(Object object, floatvalue) {

mIsStartWaterAnim=true;

mWaterWidth= value;

}

},0f,1.0f);

mWaterAnimator.addListener(newSimpleAnimatorListener() {

@Override

public voidonAnimationStart(Animator animation) {

super.onAnimationStart(animation);

mIsStartWaterAnim=true;

}

@Override

public voidonAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

mIsStartWaterAnim=false;

}

});

mWaterAnimator.setDuration(1000);

mWaterAnimator.start();

在画水波纹是首先就是要确定水波纹出现的区域不能超过最圆的区域   所以生成这个水波纹的坐标的时候使用的外圈圆的直径作为生成随机数的种子  这样 生成的 水波纹的x  y坐标就在这个区域中

然后还是同样的为了同样的构造函数创建一个ObjectAnimator对象   然后还是同样的搞一个渐变的系数    这里用了一个boolean去控制这个水波纹是不是要画在画布上   如果不使用boolean会出现一次画完后 不会自动消失  

if(mIsStartWaterAnim) {

// 画水波纹

// 画内圈固定的圆

initPaint(mWaterColor,0,255,Paint.Style.FILL);

canvas.drawCircle(mWaterX,mWaterY,6,mPaint);

// 画外圈扩散的圆

initPaint(mWaterColor,10,(int) ((1-mWaterWidth) *255),Paint.Style.FILL);

floatcircleWidth =mWaterWidth*10+6;

canvas.drawCircle(mWaterX,mWaterY,circleWidth,mPaint);

}

这里的画水波纹的具体做法就是画一个固定的小圆点   然后接着 在同一个坐标点上 换一个不断扩大并且颜色不断变浅的圆  水波纹效果就出来了

因为在构造函数中传入的透明度是从0-1.0 所以这里在通过系数计算透明度时 就是用了1-系数   这样就是从不透明到透明   然后同样把这个系数*10 就是一个整数了  这样一个大于1的整数乘上内圈固定圆的大小就可以画一个不断扩大的圆  这样水波纹效果就完成 

最后怎么控制这个水波纹效果每隔2s或者5s出现一次呢 

privateRunnablemAnimRunnable=newRunnable() {

       @Override

            public voidrun() {

                   startWaterAnim();

                   postDelayed(this,2000);

        }

};

这里就写了一个线程去启动这个动画 接着就是调用postDelayed延迟2s后执行一次


启动2s后去执行画水波纹的动画

 这样就把启动画水波纹动画的线程启动了  内部又2s后执行一次  这样就循环每2s执行一次画水波纹的动画了。

最后 ObjectAnimator 会出现内存泄漏    还有使用ValueAnimator 是会直接出现内存问题  可以用ValueAnimator写一个动画  然后脸上Android studio就会发现内存走向会出现锯齿状  具体原因就不说了

怎么避免ObjectAnimator出现内存泄漏呢 

就是在acvtivity 的onDestory()的时候去移除这个动画

public void  cancelAnim() {

      removeCallbacks(mAnimRunnable);

          if  (mCircleAnimator!=null) {

                mCircleAnimator.cancel();

             }

           if(mWaterAnimator!=null) {

                 mWaterAnimator.cancel();

              }

}

首先记得移除这个控件中的线程   然后直接把两个动画calcel()调就可以了 

自定义动画基本就完成了   欢迎拍砖  

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容