Android 动画
目录
Android 动画 1
一. 帧动画 3

  1. Xml实现: 3
  2. 帧动画的优缺点: 3
  3. 帧动画原理 4
    二. 补间动画 5
  4. 补间动画分类: 6
  5. Xml实现: 6
  6. 补间动画优缺点: 8
    三. 属性动画 8
  7. Xml实现: 9
  8. java代码实现: 10
  9. 自定义属性动画 12
  10. 属性动画优缺点: 13
  11. 属性动画原理 13
    四. 插值器Interpolator 14
  12. 主要分类: 15
  13. Xml实现: 16
  14. Java实现: 16
    4.估值器 17
    五. 自定义动画之使用Canvas绘制View动画 17
  15. Drawable与BitMap对比 18
  16. Bitmap(位图): 18
  17. 绘图工具Paint 19
  18. 绘图工具Canvas 22
  19. 绘图工具Path 24
  20. 制作动画 25
    六.自定义动画之路径动画(PathMeasure) 30
    1。比如一个动画画一个圆 30
    七.其他动画 32
    1、触摸反馈动画 32
  21. 视图状态变化动画 32
  22. 揭露动画 32
    4.跳转动画 33
  23. 矢量图动画(Vector 动画) 33

动画分类

一.帧动画
帧动画:是将一张一张的图片连贯起来播放,从而产生视觉上的动画效果。可以说,图片资源决定了这种方式可以实现怎样的动画。

  1. Xml实现:
    文件路径:src/drawable/animation_1
<animation-list xmlns:...
android:oneshot=”false”>
   <item android:drawable=”@drawable/img001” android:duration=”100”/>
   ......
</animaton-list>

Java 启动动画步骤:1.控件加载动画文件 2.创建动画(AnimationDrawable)实例,3.启动动画

//ImageView 加载动画
ImageView imgview = (ImageView)findByView(R.id.);
Imgview.setImageResource(R.drawable.animation_1);
//创建动画实例并启动动画
AnimationDrawable animation = (AnimationDrawable)imgview.getDrawable();
Animation.start();
  1. 帧动画的优缺点:
    优点:表演细腻,动画效果基本没有限制,几乎可以表现任何效果,系统提供标准API接口;
    可以控制帧率,控制每帧图片显示多少时间。
    缺点:内容制作工作量大,输出的文件大,每帧都由制作方决定,帧与帧之间连贯性不是很自然也不是很好,效果一旦制作完成,无法调整,除非重新绘制相关文件。并且初次加载时cpu占用高、加载完成后内存占用高。加载时调用Resource加载Drawable方法会对加载的Bitmap进行缓存,加载后图片会一直占用内存。可以手动进行释放、但是释放后再次加载使用会报错。
  2. 帧动画原理
    系统将帧动画封装成AnimationDrawable,AnimationDrawable继承自DrawableContainer、实现Animatable和Runnable接口。DrawableContainer继承了Drawable,DrawableContainer管理了一组Drawable,重写了draw方法,draw方法里面调用mCurrDrawable和mLastDrawable的draw方法,

AnimationDrawable 继承DrawableContainer ,重写了inflate方法,该方法用于从xml文件加载drawable。

inflate方法里面调用inflateChildElements方法将xml里面配置的item全部加载,并将drawable加载到内存,见下方代码。
从代码可以看出AnimationDrawable 是一次性将xml配置的所有图片全部加载到内存,这意味着加载AnimationDrawable时cpu占用率会飙升、加载完成后会占用大量内存。这也是AnimationDrawable的缺点,但加载完成后之后进行播放时会比较流畅。

二.补间动画
补间动画:开发者通过指定”开始帧”和”结束帧” 2个关键帧,而动画变化的”中间帧”由系统计算补齐。

  1. 补间动画分类:
    AlphaAnimation:透明度渐变效果,创建时许指定开始以及结束透明度,还有动画的持续 时间,透明度的变化范围(0,1),0是完全透明,1是完全不透明;对应标签!

ScaleAnimation:缩放渐变效果,创建时需指定开始以及结束的缩放比,以及缩放参考点, 还有动画的持续时间;对应标签!

TranslateAnimation:位移渐变效果,创建时指定起始以及结束位置,并指定动画的持续 时间即可;对应标签!

RotateAnimation:旋转渐变效果,创建时指定动画起始以及结束的旋转角度,以及动画 持续时间和旋转的轴心;对应标签!

AnimationSet:组合渐变,就是前面多种渐变的组合,对应标签!
2. Xml实现:
文件路径:src/anim/xxx.xml

1)alpha_anim.xml 动画实现

<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:toAlpha="0.0" />

2)scale.xml 动画实现

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXScale="0.0"
    android:fromYScale="0.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1.0"
android:toYScale="1.0"/>

3)translate.xml 动画实现

<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:fromYDelta="0%p"
    android:toYDelta="-100%p"
    android:duration="1000">
</translate>

4)rotate.xml 动画实现

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="540"
    android:duration="2000"
    android:fillBefore="true"
    android:repeatCount="4"
    android:repeatMode="reverse"
    android:interpolator="@android:anim/cycle_interpolator"
    />

在java中使用动画

Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
img = (ImageView) findViewById(R.id.img);
img.startAnimation(animation);

Set标签实现多个补间动画组合使用

<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set></set>

Set标签下:
Interpolator :控制动画得播放速率,即播放的快慢节奏
pivotX和pivotY:可以是float 也可以是百分比。
3. 补间动画优缺点:

  1. 补间动画,非常少的资源依赖,
  2. 系统通过标准API接口
  3. 只支持4种渐变类型:平移,旋转,缩放,透明度。
  4. 只是显示的位置变化,但View本身响应位置并没有变,点击事件仍然在原处响应。故View的属性并没有真实变化。
  5. 做复杂动画又太复杂,
  6. 但对于帧动画来说,动画更连贯自然。
    三.属性动画
    属性动画:通过改变对象的属性(有get set方法的属性)来产生动画效果。
  7. Xml实现:
    src/animator/anim_file.xml
<animator>  对应代码中的ValueAnimator
<objectAnimator>  对应代码中的ObjectAnimator
<set>  对应代码中的AnimatorSet

示例:
1)整型属性:

<animator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="0"  
    android:valueTo="100"  
android:valueType="intType"/>

2)浮点型属性:

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"  
    android:valueFrom="1"  
    android:valueTo="0"  
    android:valueType="floatType"  
android:propertyName="alpha"/>

3)动画组合

<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:ordering="sequentially" >  
  
    <objectAnimator  
        android:duration="2000"  
        android:propertyName="translationX"  
        android:valueFrom="-500"  
        android:valueTo="0"  
        android:valueType="floatType" >  
    </objectAnimator>  
  
    <set android:ordering="together" >  
        <objectAnimator  
            android:duration="3000"  
            android:propertyName="rotation"  
            android:valueFrom="0"  
            android:valueTo="360"  
            android:valueType="floatType" >  
        </objectAnimator>  
  
        <set android:ordering="sequentially" >  
            <objectAnimator  
                android:duration="1500"  
                android:propertyName="alpha"  
                android:valueFrom="1"  
                android:valueTo="0"  
                android:valueType="floatType" >  
            </objectAnimator>  
            <objectAnimator  
                android:duration="1500"  
                android:propertyName="alpha"  
                android:valueFrom="0"  
                android:valueTo="1"  
                android:valueType="floatType" >  
            </objectAnimator>  
        </set>  
    </set>  
  </set>

Java 启动动画

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);  
animator.setTarget(view);  
animator.start();
  • java代码实现:
    属性动画核心类:
  • ObjectAnimator 对象动画
  • ValueAnimator 值动画
  • PropertyValueHolder 用于同时执行多个动画
  • TypeEvaluator估值器
  • AnimatorSet 动画集合
  • Interpolator 差值器

ObjectAnimator 是继承 ValueAnimator 类,核心类还是ValueAnimator ,ObjectAnimator 类 比较常用,使用也比较广泛。

使用示例: 实现TextView的透明度渐变效果
1)对象动画:ObjectAnimator

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
animator.setDuration(5000);  
animator.start();

2)值动画:ValueAnimator ,float值变化

ValueAnimator anim = ValueAnimator.ofFloat(0f, 5f, 3f, 10f);  
anim.setDuration(5000);  
anim.setRepeatCount();
anim.setRepeatMove(ValueAnimator.RESTART)
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
              //要变化的业务逻辑属性
 			  alpha= (float) animation.getAnimatedValue();
            }
        });
anim.start();

整数值变化:0-100
ValueAnimator anim = ValueAnimator.ofInt(0, 100);

3)组合动画 :AnimatorSet

after(Animator anim)   将现有动画插入到传入的动画之后执行
after(long delay)   将现有动画延迟指定毫秒后执行
before(Animator anim)   将现有动画插入到传入的动画之前执行
with(Animator anim)   将现有动画和传入的动画同时执行

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);  
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
AnimatorSet animSet = new AnimatorSet();  
animSet.play(rotate).with(fadeInOut).after(moveIn);  
animSet.setDuration(5000);  
animSet.start();

4)动画监听:Animator
增加监听

anim.addListener(new AnimatorListener() {  
    @Override  
    public void onAnimationStart(Animator animation) {  
    }  

    @Override  
    public void onAnimationRepeat(Animator animation) {  
    }  
  
    @Override  
    public void onAnimationEnd(Animator animation) {  
    }  
  
    @Override  
    public void onAnimationCancel(Animator animation) {  
    }  
});

增加监听适配器

anim.addListener(new AnimatorListenerAdapter() {  
    @Override  
    public void onAnimationEnd(Animator animation) {  
    }  
});
  1. 自定义属性动画
    属性动画实际就是不断改变View属性值,通过设置对象的setXXX()方法改变属性和获取getXXX()方法获取属性。特别是自定义的View,也有实现setXXX()和getXXX(),在setXXX()方法中设置属性值,在getXXX()获取属性值,实现对应的动画。例如动画改变View的宽度:
/********************
     * 获取layout宽度
     * @return
     */
    public int getLayoutWight(){
        int width = mView.getLayoutParams().width;

        return width;
    }

    /********************
     * 设置layout宽度
     * @param wight
     */
    public void setLayoutWight(int wight){
        mView.getLayoutParams().width = wight;
        mView.requestLayout();
}

也就是实现setXXX和getXXX(XXX是“LayoutWight”),属性设置为“LayoutWight”即可
ObjectAnimator.ofInt(View, “LayoutWight”, 0, 500);
4. 属性动画优缺点:
优点:

  1. 可以对任意java对象进行操作,对属性值进行操作。
  2. 可自定义各种动画效果,系统提供标准API接口调用
  3. 虽然对任意java对象操作,但是只作用于对象和对象的属性。
  4. 不具有复杂的绘制能力,但可以辅助Paint对象绘制复杂图形。
  5. 是补间动画的扩展,性能上优于帧动画很多。

缺点:

  1. ValueAnimator通过底层vsync信号进行回调onAnimationUpdate方法,vsync信号16.6ms发送一次,即onAnimationUpdate 16.6ms刷新一次,如果在回调中进行界面刷新操作,则屏幕刷新率为60fps,如果机子性能欠缺会对机子造成压力。
  2. 属性动画原理
  3. 流程图
  4. 原理介绍
    ValueAnimator实现原理是通过Choreographer向SurfaceFlinger注册一个vsync信号监听,收到vsync信号回调后通过回调的时间片计算出当前animator的播放因子,再回调给注册的ValueAnimator.AnimatorUpdateListener.onAnimationUpdate方法。
    回调完成后判断动画是否结束,如未结束则再次注册vsync监听。vsync信号16.6ms回调一次。因此onAnimationUpdate方法16.6ms回调一次。

四.插值器Interpolator
Interpolator:插值器,API中固定的算法,可以实现动画过程中的加速,减速,张力,弹跳,周期,线性,正弦,等等。

  1. 主要分类:

类型:AccelerateDecelerateInterpolator
Xml: @android:anim/accelerate_decelerate_interpolator
说明:其变化开始和结束速率较慢,中间加速

类型: AccelerateInterpolator
Xml: @android:anim/accelerate_interpolator
效果: 其变化开始速率较慢,后面加速

类型:DecelerateInterpolator
Xml: @android:anim/decelerate_interpolator
效果: 其变化开始速率较快,后面减速

类型:LinearInterpolator
Xml: @android:anim/linear_interpolator
效果:其变化速率恒定

类型:AnticipateInterpolator
Xml: @android:anim/anticipate_interpolator
效果:其变化开始向后甩,然后向前

类型:AnticipateOvershootInterpolator
Xml:@android:anim/anticipate_overshoot_interpolator
效果:其变化开始向后甩,然后向前甩,过冲到目标值,最后又回到了终值

类型:OvershootInterpolator
Xml: @android:anim/overshoot_interpolator
效果:其变化开始向前甩,过冲到目标值,最后又回到了终值

类型:BounceInterpolator
Xml: @android:anim/bounce_interpolator
效果:其变化在结束时反弹

类型:CycleInterpolator
Xml: @android:anim/cycle_interpolator
效果:循环播放,其速率为正弦曲线

类型:FastOutLinearInInterpolator
效果:其变化先加速然后匀速,本质还是加速运动,和Accelerate Interpolator类似

类型:LinearOutSlowInInterpolator
效果:其变化先匀速再减速,和Decelerate Interpolator类似 android5.0

类型:FastOutSlowInInterpolator
效果:其变化是先加速,然后减速,和Accelerate Decelerate Interpolator类似 android5.0

类型:TimeInterpolator
说明: 一个接口,可以自定义插值器 android5.0
2. Xml实现:
一般在动画xml中加入:

android:interpolator="@android:anim/accelerate_interpolator"

调整参数:

res/anim/accelerate_interpolator.xml
<accelerateInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
                        android:factor="2">
</accelerateInterpolator>
  1. Java实现:
无参数
animation.setInterpolator(new AccelerateInterpolator());
参数:
animation.setInterpolator(new AccelerateInterpolator(2));
xml配置参数
animation.setInterpolator(AnimationUtils.loadInterpolator(this,R.anim.my_accelerate_interpolator));

自定义插值器:
只需要继承Interpolator 实现 getInterpolation方法

public class HesitateInterpolator implements Interpolator {
 
    public HesitateInterpolator() {}
 
    @Override
    public float getInterpolation(float input) {
        float x = 2.0f * input - 1.0f;
        return 0.5f * (x * x * x + 1.0f);
}
}

4.估值器
根据当前属性改变的百分比来计算改变后的属性值。
插值器决定属性值随时间变化的规律;而具体变化属性数值则交给估值器去计算。
系统已有的估值器:
①IntEvaluator:针对整型属性
②FloatEvaluator:针对浮点型属性
③ArgbEvaluator:针对Color属性
也可自定义估值器
一般同差值器配合使用,实现属性动画的非线性变化。
五.自定义动画之使用Canvas绘制View动画
首先View动画的绘制 需要以下步骤
1)绘制静态图
2)绘制动态逻辑
3)增加事件逻辑
主要用View的OnDraw方法去绘制。

Drawable:通用的图形对象,用于装载常用格式的图像,既可以是PNG,JPG这样的图像, 有13种Drawable类型的可视化对象!我们可以理解成一个用来放画的——画框!

Bitmap(位图):我们可以把他看作一个画架,我们先把画放到上面,然后我们可以 进行一些处理,比如获取图像文件信息,做旋转切割,放大缩小等操作!

Canvas(画布):如其名,画布,我们可以在上面作画(绘制),你既可以用Paint(画笔), 来画各种形状或者写字,又可以用Path(路径)来绘制多个点,然后连接成各种图形!

Matrix(矩阵):用于图形特效处理的,颜色矩阵(ColorMatrix),还有使用Matrix进行图像的 平移,缩放,旋转,倾斜等!

  1. Drawable与BitMap对比
  2. 图片加载:Drawable与BitMap 都是加载图片的工具,但Drawable保存图片对象,占用更小的空间,而BitMap 保存图片对象需要很大的内存空间(图片分辨率*位图类别位数),所以BitMap很容易OOM,一般在使用中要回收BitMap.
  3. 图片操作:BitMap可以支持像素操作和色差操作,Drawable在图片操作上比较繁琐。
  4. 绘图:,BitMap经常用来新建空白画布,而要用drawable绘图,就需要自定义Drawable.
  5. Bitmap(位图):
    在android中 对图像的操作其实就是对位图的操作。主要存储jpg,png,gif格式的图片数据。

Bitmap图片资源加载:
BitmapDrawable:通过构造一个BitmapDrawable的对象加载图片,然后通过该类来获取 Bitmap。也可以通过xml 来描述。这是最简单的图片加载方法。
BitmapFactory:图片加工厂,有很多的图片加载方法。
public static Bitmap decodeStream(InputStream is)
从输入流中读取图片数据并转换成 Bitmap 对象
public static Bitmap decodeByteArray(byte[] data, int offset, int length)
从字节数组中读取图片数据并转换成 Bitmap 对象
public static Bitmap decodeResource(Resources res, int id)
从 Android 的 drawable 资源(res/drawable)目录中读取图片数据并转换成 Bitmap 对象、
public static Bitmap decodeFile(String pathName)
从图片文件中读取图片数据并转换成 Bitmap 对象

Bitmap 相关方法:
普通方法
public boolean compress (Bitmap.CompressFormat format, int quality, OutputStream stream) 将位图的压缩到指定的OutputStream,可以理解成将Bitmap保存到文件中!format:格式,PNG,JPG等;quality:压缩质量,0-100,0表示最低画质压缩,100最大质量(PNG无损,会忽略品质设定)stream:输出流 返回值代表是否成功压缩到指定流!
void recycle():回收位图占用的内存空间,把位图标记为Dead
boolean isRecycled():判断位图内存是否已释放
int getWidth():获取位图的宽度
int getHeight():获取位图的高度
boolean isMutable():图片是否可修改
int getScaledWidth(Canvas canvas):获取指定密度转换后的图像的宽度
int getScaledHeight(Canvas canvas):获取指定密度转换后的图像的高度
静态方法:
Bitmap createBitmap(Bitmap src):以src为原图生成不可变得新图像
Bitmap createScaledBitmap(Bitmap src, int dstWidth,int dstHeight, boolean filter):以src为原图,创建新的图像,指定新图像的高宽以及是否变。
Bitmap createBitmap(int width, int height, Config config):创建指定格式、大小的位图
Bitmap createBitmap(Bitmap source, int x, int y, int width, int height)以source为原图,创建新的图片,指定起始坐标以及新图像的高宽。
public static Bitmap createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter)

Bitmap回收:
Bitmap是一种非常占用资源的对象,很容易导致app崩溃,所以要及时回收。
public final boolean isRecycled()
判断是否已回收,返回 true 表示内存已被回收
public void recycle()
回收 Bitmap 内存,同一个 Bitmap 对象不能连续回收多次,所以在回收之前最好是判断。不过从源码中发现其实该方法已经自己判断过了。常见的回收 Bitmap 资源的代码形如(bmp 为 Bitmap 对象):
if(bmp!= null&&!bmp.isRecycled()){
bmp.recycle();
System.gc();//ᨀ醒 JVM 释放资源
bmp = null;
}

Bitmap的使用示例:
逻辑实现:抠出图片的一角
代码实现:

Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.mipmap.pic_meizi);
Bitmap bitmap2 = Bitmap.createBitmap(bitmap1,100,100,200,200);
img_bg = (ImageView) findViewById(R.id.img_bg);
img_bg.setImageBitmap(bitmap2);

注:Bitmap 一定要记得 使用后要回收。
3. 绘图工具Paint
就是画笔,用于设置绘制风格,如:线宽(笔触粗细),颜色,透明度和填充风格等 直接使用无参构造方法就可以创建Paint实例:Paint paint = new Paint( );

我们可以通过下述方法来设置Paint(画笔)的相关属性,另外,关于这个属性有两种, 图形绘制
相关与文本绘制相关:
setARGB(int a,int r,int g,int b): 设置绘制的颜色,a代表透明度,r,g,b代表颜色值。

setAlpha(int a): 设置绘制图形的透明度。

setColor(int color): 设置绘制的颜色,使用颜色值来表示,该颜色值包括透明度和RGB颜色。

setAntiAlias(boolean aa): 设置是否使用抗锯齿功能,会消耗较大资源,绘制图形速度会变慢。

setDither(boolean dither): 设定是否使用图像抖动处理,会使绘制出来的图片颜色更加平滑和饱满,图像更加清晰

setFilterBitmap(boolean filter): 如果该项设置为true,则图像在动画进行中会滤掉对Bitmap图像的优化操作, 加快显示速度,本设置项依赖于dither和xfermode的设置

setMaskFilter(MaskFilter maskfilter): 设置MaskFilter,可以用不同的MaskFilter实现滤镜的效果,如滤化,立体等

setColorFilter(ColorFilter colorfilter): 设置颜色过滤器,可以在绘制颜色时实现不用颜色的变换效果

setPathEffect(PathEffect effect) 设置绘制路径的效果,如点画线等

setShader(Shader shader): 设置图像效果,使用Shader可以绘制出各种渐变效果

setShadowLayer(float radius ,float dx,float dy,int color):在图形下面设置阴影层,产生阴影效果, radius为阴影的角度,dx和dy为阴影在x轴和y轴上的距离,color为阴影的颜色

setStyle(Paint.Style style): 设置画笔的样式,为FILL,FILL_OR_STROKE,或STROKE

setStrokeCap(Paint.Cap cap): 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的图形样式, 如圆形样Cap.ROUND,或方形样式Cap.SQUARE

setSrokeJoin(Paint.Join join): 设置绘制时各图形的结合方式,如平滑效果等

setStrokeWidth(float width): 当画笔样式为STROKE或FILL_OR_STROKE时,设置笔刷的粗细度

setXfermode(Xfermode xfermode): 设置图形重叠时的处理方式,如合并,取交集或并集,经常用来制作橡皮的擦除效果

setFakeBoldText(boolean fakeBoldText): 模拟实现粗体文字,设置在小字体上效果会非常差

setSubpixelText(boolean subpixelText): 设置该项为true,将有助于文本在LCD屏幕上的显示效果

setTextAlign(Paint.Align align): 设置绘制文字的对齐方向

setTextScaleX(float scaleX): 设置绘制文字x轴的缩放比例,可以实现文字的拉伸的效果

setTextSize(float textSize): 设置绘制文字的字号大小

setTextSkewX(float skewX): 设置斜体文字,skewX为倾斜弧度

setTypeface(Typeface typeface): 设置Typeface对象,即字体风格,包括粗体,斜体以及衬线体,非衬线体等

setUnderlineText(boolean underlineText): 设置带有下划线的文字效果

setStrikeThruText(boolean strikeThruText): 设置带有删除线的效果

setStrokeJoin(Paint.Join join): 设置结合处的样子,Miter:结合处为锐角, Round:结合处为圆弧:BEVEL:结合处为直线

setStrokeMiter(float miter):设置画笔倾斜度

setStrokeCap (Paint.Cap cap):设置转弯处的风格 其他常用方法:

float ascent( ):测量baseline之上至字符最高处的距离

float descent():baseline之下至字符最低处的距离

int breakText(char[] text, int index, int count, float maxWidth, float[] measuredWidth): 检测一行显示多少文字

clearShadowLayer( ):清除阴影层

这个是android中字符的结构图:

setXfermode(Xfermode xfermode):设置图形重叠时的处理方式,如合并,取交集或并集, 经常用来制作橡皮的擦除效果!参数1:PorterDuffXfermode 构造方法- PorterDuffXfermode xfermode = new PorterDuffXfermode (PorterDuff.Mode mode) 而Android给我们提供了16种图片混排模式,简单点可以 理解为两个图层按照不同模式,可以组合成不同的结果显示出来!16种混排模式的结果图如下:

这里两个图层:先绘制的图是目标图(DST),后绘制的图是源图(SRC)!
当然,在文档中我们发现可供使用的模式并不是16种,而是18种,新增了ADD和OVERLAY两种模式!

  1. 绘图工具Canvas
    画笔有了,接着就到画布(Canvas),画布主要用来画几何点,线,面,图形,区域,放置图片以及自身的移动,缩放,旋转方法。常用方法如下:

首先是构造方法,Canvas的构造方法有两种:

Canvas(): 创建一个空的画布,可以使用setBitmap()方法来设置绘制具体的画布。

Canvas(Bitmap bitmap): 以bitmap对象创建一个画布,将内容都绘制在bitmap上,因此bitmap不得为null。

接着是 1.drawXXX()方法族:以一定的坐标值在当前画图区域画图,另外图层会叠加, 即后面绘画的图层会覆盖前面绘画的图层。 比如:

drawRect(RectF rect, Paint paint) :绘制区域,参数一为RectF一个区域

drawPath(Path path, Paint paint) :绘制一个路径,参数一为Path路径对象

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) : 贴图,参数一就是我们常规的Bitmap对象,参数二是源区域(这里是bitmap), 参数三是目标区域(应该在canvas的位置和大小),参数四是Paint画刷对象, 因为用到了缩放和拉伸的可能,当原始Rect不等于目标Rect时性能将会有大幅损失。

drawLine(float startX, float startY, float stopX, float stopY, Paintpaint) : 画线,参数一起始点的x轴位置,参数二起始点的y轴位置,参数三终点的x轴水平位置, 参数四y轴垂直位置,最后一个参数为Paint 画刷对象。

drawPoint(float x, float y, Paint paint): 画点,参数一水平x轴,参数二垂直y轴,第三个参数为Paint对象。

drawText(String text, float x, floaty, Paint paint) : 渲染文本,Canvas类除了上面的还可以描绘文字,参数一是String类型的文本, 参数二x轴,参数三y轴,参数四是Paint对象。

drawOval(RectF oval, Paint paint):画椭圆,参数一是扫描区域,参数二为paint对象;

drawCircle(float cx, float cy, float radius,Paint paint): 绘制圆,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint): 画弧,参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,参数二是起始角 (度)在电弧的开始,参数三扫描角(度)开始顺时针测量的,参数四是如果这是真的话,包括椭圆中心的电 弧,并关闭它,如果它是假这将是一个弧线,参数五是Paint对象;

2.clipXXX()方法族:在当前的画图区域裁剪(clip)出一个新的画图区域,这个画图区域就是canvas 对象的当前画图区域了。比如:clipRect(new Rect()),那么该矩形区域就是canvas的当前画图区域

3.save()和restore()方法:save( ):用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作!restore():用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。 save()和restore()要配对使用(restore可以比save少,但不能多),若restore调用次数比save多,会报错!

4.translate(float dx, float dy): 平移,将画布的坐标原点向左右方向移动x,向上下方向移动y.canvas的默认位置是在(0,0)

5.scale(float sx, float sy):扩大,x为水平方向的放大倍数,y为竖直方向的放大倍数

6.rotate(float degrees):旋转,angle指旋转的角度,顺时针旋转

  1. 绘图工具Path
    简单点说就是描点,连线~在创建好我们的Path路径后,可以调用Canvas的drawPath(path,paint) 将图形绘制出来~常用方法如下:

addArc(RectF oval, float startAngle, float sweepAngle:为路径添加一个多边形

addCircle(float x, float y, float radius, Path.Direction dir):给path添加圆圈

addOval(RectF oval, Path.Direction dir):添加椭圆形

addRect(RectF rect, Path.Direction dir):添加一个区域

addRoundRect(RectF rect, float[] radii, Path.Direction dir):添加一个圆角区域

isEmpty():判断路径是否为空

transform(Matrix matrix):应用矩阵变换

transform(Matrix matrix, Path dst):应用矩阵变换并将结果放到新的路径中,即第二个参数。
更高级的效果可以使用PathEffect类!
几个To:

moveTo(float x, float y):不会进行绘制,只用于移动移动画笔

lineTo(float x, float y):用于直线绘制,默认从(0,0)开始绘制,用moveTo移动! 比如
mPath.lineTo(300, 300); canvas.drawPath(mPath, mPaint);

quadTo(float x1, float y1, float x2, float y2): 用于绘制圆滑曲线,即贝塞尔曲线,同样可以结合moveTo使用!

rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) 同样是用来实现贝塞尔曲线的。 (x1,y1) 为控制点,(x2,y2)为控制点,(x3,y3) 为结束点。 Same as cubicTo, but the coordinates are considered relative to the current point on this contour.就是多一个控制点而已~ 绘制上述的曲线: mPath.moveTo(100, 500); mPath.cubicTo(100, 500, 300, 100, 600, 500); 如果不加上面的那个moveTo的话:则以(0,0)为起点,(100,500)和(300,100)为控制点绘制贝塞尔曲线

arcTo(RectF oval, float startAngle, float sweepAngle): 绘制弧线(实际是截取圆或椭圆的一部分)ovalRectF为椭圆的矩形,startAngle 为开始角度, sweepAngle 为结束角度。

  1. 制作动画
    制作动画的步骤:
    1)提取目标动画的元素,分析哪些元素是静态,哪些是动态,哪些是背景。
    2)绘制静态图,将静态元素和动态元素以及背景绘制出来。
    3)绘制动画,制作动态元素的动态效果。
    4)Touch监听事件

实例:
绘制运动的马路路基标识线动画。

逻辑:

  1. 先绘制4根长矩形,填充白色,并制作上方部分区域透明渐变叠加效果
  2. 分别通过统一改变4根白色长矩形的坐标,来改变矩形的位置,从而实现动画效果。
  3. 增加Touch事件:点击 动画开启,再点击 动画停止。

代码如下:

package com.u_fairy.myview;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.Xfermode;
import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
/**
 *
 * 画公路路基
 */
public class MyView3 extends View {
    private Canvas canvas;
    private Paint paint,paint2;
    private Path path;
    

    public MyView3(Context context) {
        this(context,null);
    }

    public MyView3(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public MyView3(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init(){
        canvas  = new Canvas();
        paint = new Paint();
        paint2 = new Paint();

        paint.setAlpha(255);
        paint.setStrokeWidth(10);
        paint.setStrokeCap(Paint.Cap.ROUND);
        paint.setStyle(Paint.Style.FILL);
//        paint.setShadowLayer(10,10,10, Color.GRAY);
        paint.setAntiAlias(true); //防锯齿
        paint.setDither(true); //防抖

        paint.setColor(Color.parseColor("#ffffff"));
    }

    int width ;
    int height;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        width = w;
        height = h;
    }

    int firstRaw =0;

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);


//        canvas.rotate(-10);
        drawSector(canvas,150,50,-300,300,100);
        drawSector(canvas,650,50,-300,300,100);

        if(firstRaw<400) {
            firstRaw = firstRaw + 10;
        }else{
            firstRaw =0;
        }

        if(!isDetached) {
            invalidate();
        }
    }

   // top start:-300
    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public void drawSector(Canvas canvas, int left, int mWidth, int top, int mHight, int disH){
//        canvas.save();
        for(int i=0;i<4;i++) {
            Rect rect = new Rect(left, top+firstRaw, left + mWidth, top + mHight+firstRaw);
            canvas.drawRect(rect, paint);
            top  = top+mHight +disH;
        }

        int as = canvas.save();
        drawslider(canvas,left,mWidth);
        canvas.restoreToCount(as);

    }

    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);

    public void drawslider(Canvas canvas,int left,int mWidth){
        LinearGradient lg=new LinearGradient(left,0,left+mWidth,500,Color.parseColor("#00ffffff"),
                Color.parseColor("#ffffffff"), Shader.TileMode.CLAMP);

        paint2.setShader(lg);
        paint2.setXfermode(mXfermode);

        canvas.drawRect(left,0,left+mWidth,500,paint2);


        paint2.setXfermode(null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action){
            case MotionEvent.ACTION_DOWN:
                isDetached=!isDetached;
                if(!isDetached) {
                    invalidate();
                }
                break;

        }
        return true;
    }

    private boolean isDetached =true;
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        isDetached = true;
    }

    public static int dp2px(int dp){
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp, Resources.getSystem().getDisplayMetrics());
    }
}

六.自定义动画之路径动画(PathMeasure)
PathMeasure是用来测量path的类
1。比如一个动画画一个圆
• 生成完整的目标路径
• 初始化PathMeasure对象
• PathMeasure.setPath(targetPath,true) 测量路径
• mPathMeasure.getLength(); 获取路径的总长度
• 初始化动态的路径 mDstPath
• mPathMeasure.getSegment(startD, stopD, mDstPath, true); : 根据传入的起始值和终止值(相当于要截取路径的部分),将路径赋值给mDstPath
• 使用ValueAnimator产生一个增长值来控制 终止值 如:float stopD = mAnimatedValue * mLength;
• 最后将 mDstPath 绘制出来,就可以实现路径的逐步绘制效果了

//完整的圆的路径
        mCirclePath = new Path();
        //路径绘制每段截取出来的路径
        mDstPath = new Path();

        mCirclePath.addCircle(0, 0, 200, Path.Direction.CW);

        //路径测量类
        mPathMeasure = new PathMeasure();
        //测量路径
        mPathMeasure.setPath(mCirclePath, true);

        //获取被测量路径的总长度
        mLength = mPathMeasure.getLength();

        mValueAnimator = ValueAnimator.ofFloat(0, 1);
        mValueAnimator.setDuration(2000);
        mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //获取从0-1的变化值
                mAnimatedValue = (float) animation.getAnimatedValue();
                //不断刷新绘图,实现路径绘制
                invalidate();
            }
        });


@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //必须要有lineTo(0,0)才可以实现路径的完整绘制
        mDstPath.reset();
        mDstPath.lineTo(0, 0);
        float stopD = mAnimatedValue * mLength;
        float startD = 0;

        //获取当前进度的路径,同时赋值给传入的mDstPath
        mPathMeasure.getSegment(startD, stopD, mDstPath, true);

        canvas.save();
        canvas.translate(300, 300);
        canvas.drawPath(mDstPath, mPaint);
        canvas.restore();
    }

七.其他动画
1、触摸反馈动画
触摸反馈动画就是一种点击效果,作用在可点击的 View 上时,当有点击事件时会有涟漪般的反馈效果。
2. 视图状态变化动画
主要通过StateListAnimator类实现View的视图变化
3. 揭露动画
(1):可以用在 Activity 里面的 View 动画效果,用来揭露某个隐藏 View 的显示;*
(2):也可以使用在 Activity 跳转过渡动画中。
4.跳转动画
主要用在Activity间的跳转的动画

  1. 采用overridePendingTransition(enterAnim, exitAnim)方法;
  2. android 5.0后可采用ActivityCompat.startActivity(context,intent,activityOptions)方法;
  3. ActivityOptons动画demo见activityoptions-master.zip
  4. 矢量图动画(Vector 动画)
    主要使用在1、具有动态变换效果的图标;2、也可以用在需要特定动画效果的 VectorDrawable 图片上等。