Android图形动画

转载 2016年11月24日 23:43:23

http://www.cnblogs.com/zhucai/p/android-graphics-animation.html

一、动画基础

本质

每帧绘制不同的内容。

 

基本过程

开始动画后,调用View的invalidate触发重绘。重绘后检查动画是否停止,若未停止则继续调用invalidate触发下一帧(下一次重绘),直到动画结束。

重绘时View的draw方法会被调用,根据动画的进行绘制不同的内容,如某个被绘制元素的大小变化、角度旋转、透明度变化等,这样即会产生动画。

动画的推进过程一般都会有一个变化量,这个变量会被用到draw方法内元素的绘制。一般的变量都是时间,也可以是手指移动、传感器等任何其他的变量。

 

Android中的动画支持

Animation:早期实现的让View整体做动画的类。能让View做Matrix(移动、缩放、旋转、3D旋转)和Alpha(透明)的动画。

Animator:有硬件加速后为做动画实现的类。能方便的让View整体做动画;也可以只产生随时间变化的变量,用来在onDraw里做绘图级的动画。比Animation灵活很多。

AnimationDrawable:图片逐帧动画。主要用来播放提前制作好的动画。

 

在哪个级别做动画

让整个View做动画(比如整个View平移、旋转等)很简单方便,一般调用几行代码就行。我把它称作View级的动画。

在View的draw/onDraw里通过Canvas来绘制时做动画更灵活,更精细,能力更强大。我把它称作绘图级的动画。(View级的动画本质上也是这么做的,只是Android系统帮我们做了大部分工作)

 

绘图级的动画

这篇文章主要讲绘图级的动画。

下面来一段绘图级动画的典型实现:

class MyView extends View {
    void startAnimator() {
        ValueAnimator animator = ValueAnimator.ofFloat(1f, 0f);
        animator.start();
        invalidate();
    }
    protected void onDraw(Canvas canvas) {
        if (animator.isRunning()) {
            float ratio = (Float)animator.getAnimatedValue();
            canvas.rotate(ratio*360);
            canvas.drawBitmap(bitmap, 00null);
 
            invalidate();
        }
        ...
    }
}

有了不断变化的ratio变量,绘图级动画就可以大展身手了。

绘图级动画的强大能力来自绘图API的强大能力,下面主要讲绘图API。

 

二、绘图API

Matrix

Canvas.[translate,scale,rotate,skew]方法

Matrix.set/pre/post[translate,scale,rotate,skew]方法

平移、缩放、旋转、斜切。

从使用API的角度来看,我们通过调用Canvas.translate等方法,可以使后续在此Canvas上绘制操作的绘制区域变化,如translate(5,0),则后续所有绘制操作的绘制区域都会向右移动5个像素。

原理:Canvas里有一个Matrix,Canvas上的这几个调用都会最终调用到Matrix.pre*。这个Matrix保存整个变换过程。当有Canvas.draw时,要绘制的点都会经过Matrix.mapPoints方法做一个映射。于是产生我们期望的变换效果。(事实上映射的时候只需要映射关键点,其他的是插值来的)

关于Matrix的更多信息

set/pre/post的区别:set是设置,冲掉以前的数据。pre是前乘,post是后乘,根本上讲就是生效顺序不同。具体表现效果可在网上搜索资料。

setPolyToPoly:与mapPoints方法相反,mapPoints是通过矩阵把原始点映射为目标点。setPolyToPoly是输入原始点和映射后的目标点,计算出这个矩阵。

Camera:有透视效果的3D旋转。Camera是一个生成Matrix的工具类。可用来生成有透视效果的3D旋转。

 

Canvas.draw*方法

Canvas.draw-Point/s

Canvas.draw-Line/s

Canvas.draw-Rect,RoundRect,Circle,Oval,Arc,Path

Canvas.draw-Text

Canvas.draw-Bitmap,BitmapMesh

Canvas.draw-Color,Paint

这些方法都表示绘制一个区域。绘制的区域中究竟填充什么颜色,由Paint决定。

Color,Paint,Bitmap,BitmapMesh这几个则除了指定绘制区域外,还指定了填充内容。

Path功能比较强大,可自行组织成任何形状,还可以用贝塞尔曲线。

 

这些方法基本上都很好理解,从名字上即可看出其功能。这里重点提一下drawBitmapMesh。

drawBitmapMesh是输入一个网格模型,绘制出的图片内容将依据这个网格来扭曲。可以想像成把图片画在一块有弹性的布上,当我们把布的某些区域扯动的时候,会形成画面扭曲效果。

示例:假设有个30x30大小的图片,我们建立这样的网格输入:

0,0, 15,0, 30,0,

0,15, 15,15, 30,15,

0,30, 15,30, 30,30

则图片会原样输出,没有任何扭曲。

如果我们建立这样的网格输入:

0,0, 15,12, 30,0,

0,15, 15,15, 30,15,

0,30, 15,30, 30,30

则原本[15,0]的点会被绘制到[15,12]的位置上去。图片绘制出来后,上面部分会缺一块,形成用手把图片从上边中间位置往下拉的扭曲效果。但很锐利,上面缺的一块是个三角形而不会是半圆型,通常我们希望的是半圆型,这就需要我们把这个网格建得密一些。

 

Alpha通道

每个Color里可以有四个通道ARGB,其中RGB是红绿蓝,A即Alpha通道,它通常的作用是用来作为此颜色的透明度。

因为我们的显示屏是没法透明的,因此最终显示在屏幕上的颜色里可以认为没有Alpha通道。Alpha通道主要在两个图像混合的时候生效。

默认情况下,当一个颜色绘制到Canvas上时的混合模式是这样计算的:(RGB通道) 最终颜色 = 绘制的颜色 + (1 - 绘制颜色的透明度) × Canvas上的原有颜色。

注意:

1.这里我们一般把每个通道的取值从0到255映射到0到1的浮点数表示。

2.这里等式右边的“绘制的颜色"、“Canvas上的原有颜色”都是经过预乘了自己的Alpha通道的值。如绘制颜色:0x88ffffff,那么参与运算时的每个颜色通道的值不是1.0,而是(1.0 * 0.53125 = 0.53125)。

使用这种方式的混合,就会造成后绘制的内容以半透明的方式叠在上面的视觉效果。

其实还可以有不同的混合模式供我们选择,用Paint.setXfermode,指定不同的PorterDuff.Mode

下表是各个PorterDuff模式的混合计算公式:(D指原本在Canvas上的内容dst,S指绘制输入的内容src,a指alpha通道,c指RGB各个通道)

ADD  Saturate(S + D)  
CLEAR  [0, 0]  
DARKEN  [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)]  
DST  [Da, Dc]  
DST_ATOP  [Sa, Sa * Dc + Sc * (1 - Da)]  
DST_IN  [Sa * Da, Sa * Dc]  
DST_OUT  [Da * (1 - Sa), Dc * (1 - Sa)]  
DST_OVER  [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc]  
LIGHTEN  [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)]  
MULTIPLY  [Sa * Da, Sc * Dc]  
SCREEN  [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc]  
SRC  [Sa, Sc]  
SRC_ATOP  [Da, Sc * Da + (1 - Sa) * Dc]  
SRC_IN  [Sa * Da, Sc * Da]  
SRC_OUT  [Sa * (1 - Da), Sc * (1 - Da)]  
SRC_OVER  [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc]  
XOR  [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc]  

可以发现,我们之前的默认混合模式其实就是SRC_OVER。

通过选择其他的PorterDuff模式,我们可以达到一些特殊的效果:

使用DST_OVER的话,相当于后绘制的内容作为背景在底下。

使用DST_IN/DST_OUT的话,可以裁剪Canvas里的内容,或用一张带alpha的图片mask指定哪些区域显示/不显示。

通过选择SRC_ATOP可以只在Canvas上有内容(不透明)的地方绘制。

用一张示例图来查看使用不同模式时的混合效果(src表示输入的图,dst表示原Canvas上的内容):

 

填充颜色

之前说过Canvas.draw*指定了绘制的区域。而区域里的填充颜色是由Paint来指定的。

Paint.setColor指定纯色。

Paint.setShader可指定:BitmapShaderLinearGradientRadialGradientSweepGradientComposeShader

BitmapShader:图片填充。

LinearGradient, RadialGradient, SweepGradient:渐变填充。

ComposeShader:叠加前面的某两种。可选择PorterDuff混合模式。

如果既调用了setColor,又调用了setShader,则setShader生效。如果同时用setColor或setAlpha设置了透明度,则透明度也会生效。(会和Shader的透明度叠加)

如果使用drawBitmap输入一个只有alpha的图片(可用Bitmap.extractAlpha方法获得),则会以alpha图片为mask,绘制出shader/color的颜色。

 

ColorFilter

通过ColorFilter可以对一次绘制的所有像素做一个通用处理。

Paint.setColorFilter: LightingColorFilterPorterDuffColorFilterColorMatrixColorFilter

这可以整体上改变这一次draw的内容,比如让颜色更暗、更亮等。

这里重点介绍下ColorMatrixColorFilter。

ColorMatrix是4x5矩阵,定义其每个元素如下: 

{ a, b, c, d, e,

 f, g, h, i, j,

k, l, m, n, o,

p, q, r, s, t }

 则ColorMatrix的最终运算方式如下:

R' = a*R + b*G + c*B + d*A + e;
G' = f*R + g*G + h*B + i*A + j;
B' = k*R + l*G + m*B + n*A + o;
A' = p*R + q*G + r*B + s*A + t;

可在这里方便的试验flash在线版。

 

绘图API架构

整个绘制流水线大概如下:(我们能定义的部分用蓝色表示)

考虑动画实现的时候一般从两个角度来思考:

宏观角度:有几个变化量,分别是什么。动画从开始到结束的流程。

微观角度:从某一帧上去想,在变化量为某个数值时的图像,该怎么绘制。

把这两者分开去想,就会比较清晰。

 

PPT里有示例,可以参照DEMO来熟悉:

怎么做动画.ppt

Android图形系统简介.ppt

GraphicsDemo.apk

GraphicsDemo_src.zip

 


利用Matrix对图片进行变换以及实现动画方法浅谈

Android的Animations动画效果归根结底是利用cavas根据matrix对bitmap进行绘制,不同的matrix可让bitmap进行不同的显示,变换方式有平移、旋转、伸缩、扭曲这四种,本...
  • baidu_27196493
  • baidu_27196493
  • 2016-09-27 23:11:39
  • 964

Android动画总结系列(6)——矢量图形与矢量动画

本文总结了矢量图形和矢量动画的使用方法。
  • u013478336
  • u013478336
  • 2016-08-22 16:35:44
  • 5749

玩转Android---2D图形及动画---动画分析(Tween详细分析)

原址:http://hualang.iteye.com/category/143855 在Android系统中提供了两种动画实现方式:一种是Tween动画,这种实现方式可以使视图组件移动、放大、缩小...
  • luckypeng
  • luckypeng
  • 2015-07-30 19:40:27
  • 300

ANDROID实现圆形图形不断旋转的动画

xml version="1.0" encoding="utf-8"?> set xmlns:android="http://schemas.android.com/apk/res/android" ...
  • tianxiangshan
  • tianxiangshan
  • 2012-08-01 09:05:31
  • 6686

Android自定义控件:动画类(十)----AnimatorSet联合动画的代码实现

上几篇给大家分别讲了ValueAnimator和ObjectAnimator,相比而言ObjectAnimator更为方便而且由于set函数是在控件类内部实现,所以封装性更好。而且在现实使用中一般而言...
  • xuefu_78
  • xuefu_78
  • 2016-09-02 17:38:56
  • 855

Android 抽奖 转盘 动画 实现原理详解

Android动画之旅有一段时间没有写新的内容了。我之前想的是,边学习边开发一些有用的小Demo但是一写起来就根本停不下来了。先给大家展示一个成果,后续我会将每个项目的原码和原理分析发布出来。虽然我知...
  • u010451990
  • u010451990
  • 2016-11-08 10:47:52
  • 536

声音识别动画(上)-----矩形声音识别动画

效果图: 这里边有两个声音识别动画,分别是矩形声音识别动画和线形(波浪线形)声音识别动画, 本篇先来介绍矩形声音识别动画:原理: 1. 每隔一段时间,重新绘制着界面,小矩形的高度等于总高度乘以...
  • Jeff169
  • Jeff169
  • 2017-04-16 16:16:57
  • 670

java动画、图形和极富客户端效果开发 中文版+英文版+源码 (非扫描)

  • 2014年04月18日 14:06
  • 58.04MB
  • 下载

Android 图片填充动画

前言 最近在项目中,开发下拉刷新列表时,要做一个动画,下拉的时候慢慢填充一个动画,做到一个满血复活的效果(设计师的解释,你懂得--),然后自己写了一个自定义的动画实现此效果。 代码...
  • u011916937
  • u011916937
  • 2016-04-27 10:08:39
  • 787

Android动画探索——图标依次变大的水滴效果

一直打算模仿ios,做一个安卓的水滴效果:比如有四个图标,四个图标依次出现,并由小变大。就像水滴掉落时一头大一头小一样。...
  • gagalaha
  • gagalaha
  • 2015-05-11 17:54:54
  • 3553
收藏助手
不良信息举报
您举报文章:Android图形动画
举报原因:
原因补充:

(最多只允许输入30个字)