Android自定义动画

在目前的移动端产品中,不管是app还是网页一个好看酷炫的页面总是会第一时间吸引人的眼球,那么对于android开发人员来说,要想实现一个好看的页面必然需要掌握自定义控件以及自定义动画这门技术。

1.Android原生动画

Android下已经给我们提供了几种原生动画的表现形式:

①补间动画

平移:TranslateAnimation旋转:RotateAnimation缩放:ScaleAnimation渐变:AlphaAnimation

②属性动画

ObjectAnimatior: translation(x或y),rotation(x或y),scale(x或y)
ValueAnimator:ObjectAnimatior的父类,值动画

③帧动画

AniamteDrawable
  • 注意补间动画和属性动画的最大区别:

    • 补间动画只是改变了View的显示效果,并没有真正改变View的属性
    • 属性动画是真正改变了View的属性,比如平移效果。
    • 属性动画是Android 3.0引入的

2.Android自定义动画-表现形式一

那么什么是自定义动画呢?其实不明觉厉,那就是自己根据需求定义的动画效果。因为在实际开发中,大部分的复杂酷炫的动画效果用我们Android原生提供的动画都是满足不了的,那么就需要我们自己去定义。

那么本篇文章将通过三个案例的形式给大家演示通过自定义动画的第一种表现方式-自定义控件绘制的方式

那么接下来通过一些小demo案例来进行演示如何实现一些原生动画无法实现的自定义效果。

①WIFI效果

首先看下效果图:

1)思路

根据上面的效果图我们可以发现android原生动画是无法实现的,所以我们需要自定义控件动态去绘制这样的效果,那么思路可以分为以下两步:

  1. 先绘制WIFI在满信号的情况下的视图效果,也就是静态视图
  2. 通过handler的postDelayed方法可以死循环不断执行view的invalidate()方法来达到动态绘制的效果(每次绘制需要控制绘制几个信号)

2)具体实现

那么因为我们需要去绘制这个扇形和弧线,所以首先需要去创建一个自定义的view重写它的onDraw()方法,在绘制之前可以在view创建的时候先将画笔初始化出来。

具体的难点在于第二步如何动态去绘制,可以定义一个具体的数值比如 shouldExistSignalSize 来控制每次绘制的时候绘制哪个信号,从最开始的时候只绘制第一个信号(也就是扇形),接着第二次绘制的时候需要绘制第一个和第二个信号,往后就是第一个信号,第二个信号,第三个信号;当四格信号都绘制完毕的时候记得将 shouldExistSignalSize 重置。

代码如下:

/*** Created by PeiHuan on 2017/6/24.* <p>* WIFI控件*/
public class WIFIView extends View {public WIFIView(Context context) {this(context, null);}public WIFIView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public WIFIView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private Paint paint;/*** 初始化准备*/private void init() {paint = new Paint();//画笔颜色paint.setColor(Color.BLACK);//画笔粗细paint.setStrokeWidth(6);//抗锯齿paint.setAntiAlias(true);handler.postDelayed(new Runnable() {@Overridepublic void run() {invalidate();handler.postDelayed(this,500);}},500);}private Handler handler = new Handler();/**WIFI控件宽高较小一边的长度*/private int wifiLength;@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);wifiLength = Math.min(w, h);}/*** 开始角度*/private float startAngle = -135;/*** 扇形或者弧的旋转角度*/private float sweepAngle = 90;/*** 信号大小,默认4格*/private int signalSize = 4;/**每次应该绘制的信号个数*/private float shouldExistSignalSize = 0f;@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);shouldExistSignalSize++;if(shouldExistSignalSize>4){shouldExistSignalSize=1;}canvas.save();//计算最小的扇形信号所在的圆的半径float signalRadius = wifiLength/2/signalSize;//向下平移画布,保证绘制的图形能够完全显示canvas.translate(0,signalRadius);for (int i = 0; i < signalSize; i++) {if(i>=signalSize-shouldExistSignalSize) {//定义每个信号所在圆的半径float radius = signalRadius * i;RectF rectf = new RectF(radius, radius, wifiLength - radius, wifiLength - radius);if (i < signalSize - 1) {paint.setStyle(Paint.Style.STROKE);canvas.drawArc(rectf, startAngle, sweepAngle, false, paint);} else {paint.setStyle(Paint.Style.FILL);canvas.drawArc(rectf, startAngle, sweepAngle, true, paint);}}}canvas.restore();}
}

详细代码请参考GitHub仓库:
https://github.com/zphuanlove/AnimationProject

②MUSIC效果

接下来再来看一个很常见的效果,同样也是通过自定义控件实现ondraw()去动态绘制;这也是很多目前能看到的一些音乐相关的app具有的效果,效果图如下:

1)思路

流程和思路和第一个demo类似,但产生动画的策略略有不同。

  1. 首先绘制静态效果图,剖析出整个图形由哪几部分组成:(两个圆,四段弧线)

  2. 通过不断绘制产生动画(不断更改四段弧线的起始角度)

WIFI demo我们使用的是handler的postDelayed方法造成一个死循环
这次我们可以通过在onDraw方法中调用invalidate来实现动画。

2)具体实现

具体实现同样也是在构造函数初始的时候去初始化画笔,然后在ondraw()方法中去绘制一个大圆一个小圆以及四段弧线,这里四段弧线可以分成两部分,及相对的两部分,每部分由一个大弧和一个小弧组成,两部分之间间隔180度。要绘制弧线就是要确认弧所在圆的外接矩形的左上右下,通过下图的计算可以很方便的计算出大弧所在的矩形的左上右下:

代码如下:

/*** Created by PeiHuan on 2017/6/24.* <p>* Music控件*/
public class MusicView extends View {private Paint paint;private int length;public MusicView(Context context) {this(context, null);}public MusicView(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public MusicView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}/*** 初始化操作*/private void init() {paint = new Paint();//画笔颜色paint.setColor(Color.BLACK);//画笔粗细paint.setStrokeWidth(2);//抗锯齿paint.setAntiAlias(true);//不填充paint.setStyle(Paint.Style.STROKE);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);length = Math.min(w, h);bigCircleRadius = length / 2;bigAngelRadius = length / 3;smallAngelRadius = length / 4;}/*** 大圆的半径*/private float bigCircleRadius;/*** 小圆的半径*/private float smallCircleRadius = 5f;/*** 两段大弧的半径*/private float bigAngelRadius;/*** 两段小弧的半径*/private float smallAngelRadius;private float startAngle1 = 0;private float startAngle2 = 180;private float sweepAngle = 60;@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);//绘制两个圆canvas.drawCircle(bigCircleRadius, bigCircleRadius, bigCircleRadius - smallCircleRadius, paint);//小圆粗一些paint.setStrokeWidth(3);canvas.drawCircle(bigCircleRadius, bigCircleRadius, smallCircleRadius, paint);//绘制四段弧线//两段大弧,弧度相差180度RectF rectF = new RectF(bigCircleRadius-bigAngelRadius,bigCircleRadius-bigAngelRadius,bigCircleRadius+bigAngelRadius,bigCircleRadius+bigAngelRadius);canvas.drawArc(rectF,startAngle1,sweepAngle,false,paint);canvas.drawArc(rectF,startAngle2,sweepAngle,false,paint);//两段小弧,弧度相差180度RectF rectFSmaller = new RectF(bigCircleRadius-smallAngelRadius,bigCircleRadius-smallAngelRadius,bigCircleRadius+smallAngelRadius,bigCircleRadius+smallAngelRadius);canvas.drawArc(rectFSmaller,startAngle1,sweepAngle,false,paint);canvas.drawArc(rectFSmaller,startAngle2,sweepAngle,false,paint);startAngle1+=5;startAngle2+=5;if(!isDetached) {invalidate();}}/*** 自定义控件是否脱离窗体*/private boolean isDetached;/*** 当自定义控件脱离窗体,即将销毁*/@Overrideprotected void onDetachedFromWindow() {super.onDetachedFromWindow();isDetached = true;}
}

详细代码请参考GitHub仓库:
https://github.com/zphuanlove/AnimationProject

③文字水波效果

最后一个效果就要酷炫一些了,不过代码实现起来也很简单,因为这里主要是要用到android中的一个关键技术:着色器实现。

我们先来看看效果:

1)思路

自定义TextView,在TextView的文本上添加遮盖物,并让着色器不断平移和下降,当下降完全显示文字后再移动着色器到文字顶部继续重复执行。

2)着色器Shader

简单铺垫下shader的作用,如果想要深入学习的同学可以下去自行查阅资料,这里不是本篇的重点了。

我们在用Android中的Canvas绘制各种图形时,可以通过Paint.setShader(shader)方法为画笔Paint设置shader,这样就可以绘制出多彩的图形。那么Shader是什么呢?Shader就是着色器的意思。我们可以这样理解,Canvas中的各种drawXXX方法定义了图形的形状,画笔中的Shader则定义了图形的着色、外观,二者结合到一起就决定了最终Canvas绘制的被色彩填充的图形的样子。

类android.graphics.Shader有五个子类:

  • LinearGradient 线性梯度渐变
  • RadialGradient 环形梯度渐变或者灯光渲染
  • SweepGradient 扫描梯度渐变
  • BitmapShader 图片渲染
  • ComposeShader 组合渲染

这里重点介绍下BitmapShader,因为该案例需要使用到它。

BitmapShader,顾名思义,就是用Bitmap对绘制的图形进行渲染着色,其实就是用图片对图形进行贴图。如果亲自装修过或者看过装修的同学应该知道新房在喷漆的时候会将一些不需要喷漆的地方用报纸进行包住来遮挡,那么BitmapShader也是通过的道理,比如我们想要对文字Loading进行喷色,着色,那么只需要将文字其余的地方遮住,只取图片上的颜色来对文字进行着色即可。

从字面上理论的角度理解后,再从它的构造函数上进行理解:

/*** Call this to create a new shader that will draw with a bitmap.** @param bitmap            The bitmap to use inside the shader* @param tileX             The tiling mode for x to draw the bitmap in.* @param tileY             The tiling mode for y to draw the bitmap in.*/
public BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY)

第一个参数是Bitmap对象,该Bitmap决定了用什么图片对绘制的图形进行贴图,着色。

第二个参数和第三个参数都是Shader.TileMode类型的枚举值,有以下三个取值:CLAMP 、REPEAT 和 MIRROR。

  • CLAMP表示,当所画图形的尺寸大于Bitmap的尺寸的时候,会用Bitmap四边的颜色填充剩余空间。
  • REPEAT表示,当我们绘制的图形尺寸大于Bitmap尺寸时,会用Bitmap重复平铺整个绘制的区域。
  • MIRROR 与REPEAT类似,当绘制的图形尺寸大于Bitmap尺寸时,MIRROR也会用Bitmap重复平铺整个绘图区域,与REPEAT不同的是,两个相邻的Bitmap互为镜像。

3)代码实现

首先创建一个自定义view继承TextView,并且初始化字体,初始化着色器,代码如下:

/*** Created by PeiHuan on 2017/6/25.** 水面下降效果控件*/
public class WaterTextView extends android.support.v7.widget.AppCompatTextView {public WaterTextView(Context context) {this(context,null);}public WaterTextView(Context context, @Nullable AttributeSet attrs) {this(context, attrs,0);}public WaterTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {//让当前的TextView的字体为美术字体Typeface typeface = Typeface.createFromAsset(getResources().getAssets(), "Satisfy-Regular.ttf");setTypeface(typeface);//Matrix:矩阵,可以实现视图的平移旋转等效果matrix = new Matrix();//创建一个着色器createShader();}private void createShader() {Bitmap originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.wave);int waveWidth = originalBitmap.getWidth();waveHeight = originalBitmap.getHeight();Bitmap bitmap=Bitmap.createBitmap(waveWidth, waveHeight, originalBitmap.getConfig());//创建一个画布,为了将wave的图片颜色数据写入到Bitmap中Canvas canvas=new Canvas(bitmap);//设置画布的颜色从而控制文字的着色颜色canvas.drawColor(Color.RED);canvas.drawBitmap(originalBitmap,new Matrix(),getPaint());//CLAMP:使用原来的那张图片整体//REPEAT:将原来的图片复制无数份//MIRROR:镜像,将原来的图片镜像后,写入,再镜像...shader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);getPaint().setShader(shader);shaderX = 0;shaderY = -waveHeight/2;}}

接着让波浪动起来,通过ondraw()方法调用invalidate(),控制着色器的Y轴平移,代码如下:

@Override
protected void onDraw(Canvas canvas) {super.onDraw(canvas);repeatShader();
}private void repeatShader() {shaderX +=5;shaderY +=0.1;if(shaderY >-waveHeight/2+height){shaderY = -waveHeight/2;}matrix.setTranslate(shaderX, shaderY);shader.setLocalMatrix(matrix);invalidate();
}

详细代码请参考GitHub仓库:
https://github.com/zphuanlove/AnimationProject

总结

该篇文章通过三个案例效果给大家演示了如何实现android下的自定义动画效果,不过这仅仅只是android自定义动画的第一种表现形式,接下来还会在下篇文章中继续讲解第二种形式的展现。

文中的案例在github上均有详细以及扩展代码展示,三个案例汇总到一个项目中。

Thanks!

Android自定义动画专题一相关推荐

  1. Android自定义动画专题二

    android自定义动画专题二 在上篇文章中给大家介绍了android自定义动画的第一种表现形式:view的绘制:不过这只是一种单纯利用自定义控件绘制的方式去实现:这篇文章会给大家演示如何通过自定义控 ...

  2. android 自定义loading,Android自定义动画-StarLoadingView

    今天来分享第二个自定义loading的动画,起了个名字叫 蹦跶的星星 ,还是老规矩先介绍,后上图. 实现效果在最后,GIF有点大,手机流量慎重. 介绍 首先声明做这个动画的初衷是为了学习和分享,所以从 ...

  3. Android自定义动画三-SVG动画

    Android自定义动画三-SVG动画 本篇文章主要是对SVG的一个介绍和使用,以及Android中对SVG的一个支持,从而可以帮助我们在android下很轻松的通过SVG实现一些非常酷炫的动画效果. ...

  4. Android自定义动画学习,实现左右摇摆动画

    (转载)http://johnnyg.iteye.com/blog/2074464 我们都知道Android SDK给我们提供了4种常用的动画效果分别是: AlphaAnimation:透明度变化动画 ...

  5. android 属性翻牌动画,Android自定义动画--卡牌翻牌动画

    Android系统中自带了四种动画,但是都只是平面上的并不能实现我们很常见的翻牌动画,所以今天我们就要通过自定义动画来实现翻牌动画. 要实现翻牌动画,我们需要了解三个类,一个是matrix类,一个是c ...

  6. Android 自定义动画(实现类似分享动画)

    最近在开发app中,要实现点击进入分享动画页面,然后照着每个Item的功能,来实现各自的功能 效果图如下: 首选自定义动画Activity import android.animation.Anima ...

  7. Android 自定义动画 LoadingView

    项目地址:https://github.com/CuteWiseCode/MyLoadingView 先上效果图 实现思路: 代码实现主要结合自定义view 以及动画属性的方式,根据需求调整动画的展示 ...

  8. android自定义动画插值器(Interpolator)

    前言 之前已经讲过动画相关的内容,没有接触过的读者可以看下笔者之前对android动画使用的整理. Android动画总结 (valueAnimator.objectAnimator.Animator ...

  9. Android 自定义动画view(小变大,旋转,色值)

    也不知道到看了多少的动画总结了,但是用到的时候太少,过段时间就会忘记了. 既然如此,我选择直接去动手学习,步步进阶. 效果: 上代码之前我们分析一下才会加深自己的印象: 需要画一个矩形 和 一个圆形 ...

最新文章

  1. 保障数据安全,强调科技向善,旷视发布《人工智能应用准则》
  2. java操作跨页的word cell,利用itext 生成pdf,处理cell 跨页问题 [转]
  3. Elasticsearch——Templates 模板
  4. 重写selenium 的 click()操作,使得脚本更稳定
  5. (解题报告)L1-032 Left-pad (20分)——15行代码AC
  6. pep 8 规范的一些记录
  7. CF98E Help Shrek and Donkey(纳什博弈 + 大讨论)
  8. 复制构造函数的用法及出现迷途指针问题
  9. css transtion不生效_CSS中transition属性不起作用的原因及解决方法
  10. html/css/js各类相对路径引用方法归类
  11. golang延时_Golang 定时器底层实现深度剖析
  12. 计算机信息技术知识点思维导图,思维导图信息技术的学习方法
  13. php时间格式转换成时间戳,php怎么把时间格式转换为时间戳?
  14. libtorrent实现bt客户端程序
  15. 2019年,北上广等一线城市的IT岗位饱和了么?
  16. 【最全】latex与word之间的各种转化方法和软件汇总
  17. 【Java 数据结构】树和二叉树
  18. java打字训练课程设计_JavaFX+Java打字练习软件(布局篇)
  19. c语言输出五角星程序,c语言入门之绘制五角星.doc
  20. Python 二分查找:bisect库的使用

热门文章

  1. 让ASMX支持Json格式的返回数据
  2. 好程序员打造核心教培天团,着力培养IT高级研发人才
  3. 我的世界(5)-神奇宝贝服神兽刷新概率、时间(pixelmon模组)
  4. 使用csv写入内容时如何自动分成两个单元格
  5. JSP和Servlet的区别和联系 JSP 内置对象和作用
  6. OpenCV:生成条纹图
  7. JxlExcelUtil生成Excel供SFTP推送Java实现获取目录下最新的excel
  8. IDEA关闭页面浏览器显示图标
  9. 交互媒体专题设计结课实验报告
  10. SQL基础教程MICK版 ···第三章总结