Android Animation (动画设计)

Android Animation(动画设计)

        本文主要介绍逐帧动画,补间动画,属性动画

使用简单的图片

1.Bitmap和BitmapFactory

把一个Bitmap包装成BitmapDrawable对象,调用BitmapDrawable的构造器
BitmapDrawable drawable = new BitmapDrawable(bitmap);
获取BitmapDrawable所包装的Bitmap,
Bitmap bitmap = drawable.getBitmap();

2.Bitmap的其他方法

createBitamap(Bitmap source,int x,int y,int width,int height);从源source中从指定的坐标点(x,y)开始挖取(width,height)的图像,创建新的Bitmap
createScaledBitmap(Bitmap src,int dstWidth,int dstHeight,boolean filter):对原(src)进行缩放,缩放成(dstWidth,dstHeight)
createBitmap(int width,int height,Config config):创建一个(width,height)的新位图,创建副本时调用
.......

Animation

简单变换

1.canvas变换
canvas.rotate(float degress,float px,float py):旋转变换
canvas.scale(float sx,float sy,float px,float py):缩放变换
canvas.skew(float sx,float sy):倾斜变换
canvas.translation(float dx,float dy):平移

canvas.drawTextOnPath(String text,Path path,float hOffset,float vOffset,Paint paint):沿着路径绘制文本
2.Matrix变换
setTranslate(float dx,float dy);空调之Matrix进行平移
setSkew(float kx,float ky,float px,float py):Matrix以px,py为轴心进行倾斜,kx,ky为X,Y,上的倾斜方向
setsKew(float kx,float ky)
setRotate(float degress);
setRoatate(float degress,float px,float py)以px,py为轴心进行旋转,degress控制旋转的角度
setScale(float sx,float sy);
setScale(float sx,float sy,float px,float py);Matrix以px,py为轴心进行缩放,sx,sy为缩放的比例
canvas.drawBitmap(Bitmap bitmap,Matrix matrix,Paint paint);
3.AnimationDrawable与逐帧动画
//res下定义xml动画文件
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item android:drawable="@mipmap/g1" android:duration="200"/>
    <item android:drawable="@mipmap/g2" android:duration="200"/>
    <item android:drawable="@mipmap/g3" android:duration="200"/>
</animation-list>

//MainActivity中定义
    ImageView iv = (ImageView)findIdBy(R.id.image);
    iv.setBackgroundResource(R.drawable.animation);
    AnimationDrawable ad = (AnimationDrawable) iv.getBackground();
    ad.start();
4.Tween(补间动画)与Interpolator
    AlphaAnimation:透明度改变的 (0 ~1)
    ScaleAnimation:大小缩放的动画(pivotX,pivotY)缩放中心
    TranslateAnimation:位移变化的动画
    RotateAnimation:旋转动画(pivotX,pivotY)旋转中心
    Interpolator接口,负责控制动画的变化速度,可以使四种不同的变化以(匀速,加速,减速,抛物线,)等各种速度变化
    >LinearInterpolator:动画以均匀地速度变化
    >AccelerateInterpolator:加速
    >AccelerateDecelerateInterpolator:中间加速,两边较慢
    >CycleInterpolator:循环播放特定次数,变化速度按正旋变化
    >DecelerateInterpolator:减速
//在java文件中使用
TranslateAnimation translation = new TranslateAnimation(-100,100,-100,100);
ScaleAnimation scale = new ScaleAnimation(1f,0.5f,1f,0.5f);
AlphaAnimation alpha = new AlphaAnimation(1f,0.5f);
RotateAnimation rotate = new RotateAnimation(0,180,0.5f,0.5f);
setDuration(3000);//设置时间
xxx.setFillAfter(true);//转换后保持动画的状态
iv.startAnimation(rotate);//开始
<!--xml使用xml布局定义-->
<set
    android:shareInterpolator="false"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"//使用Interpolator接口定义动画的速度
        android:fromXScale="1.0"
        android:toXScale="1.4"
        android:fromYScale="1.0"
        android:toYScale="0.6"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false"
        android:duration="700" />
    <set android:interpolator="@android:anim/decelerate_interpolator">
        <scale
            android:fromXScale="1.4"
            android:toXScale="0.0"
            android:fromYScale="0.6"
            android:toYScale="0.0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:startOffset="700"
            android:duration="400"
            android:fillBefore="false" />
        <rotate
            android:fromDegrees="0"
            android:toDegrees="-45"
            android:toYScale="0.0"
            android:pivotX="50%"
            android:pivotY="50%"
            android:startOffset="700"
            android:duration="400" />
    </set>
</set>

//Mainactivity中使用
Animation anim = AnimationUtils.loadAnimation(this, R.anim.animation);
anim。startAnimation(anim);
4.属性动画(属性动画与补间动画相比,
    补间动画:只改变了图片的位置
    属性动画:改变了位置,也改变了动画的真是坐标)
属性动画的API
Animator:提供了创建属性动画基类,只在被继承,重写时使用
ValueAnimator:(1)计算各帧的相关属性值
            (2)为指定的对象设置指定的值
ObjectAnimator:ValueAnimator的子类
AnimatorSet:Animator的子类,组合多个Animator1按照顺序播放

ValueAnimator创建动画
1.调用ValueAnimator的ofInt(),ofFloat();ofObject()静态方法创建Animator实例
2.调用ValueAnimator的setXXX()
     oa1.setDuration(3000);//持续时间
        oa1.setRepeatCount(1);重复次数
        设置重复模式
        oa1.setRepeatMode(ValueAnimator.RESTART);从头开始模式
    setRepeatMode(Animation.REVERSE);反方向执行

3.调用anim.start();方法启用
4.为ValueAnimator注册监听器AnimatorUpdateListener,在监听器上可以监听ValueAnimator改变的值
//使用ObjectAnimation分别定义不同的属性
    ObjectAnimation oa1,oa2,oa3,oa4;
    oa1 = ObjectAnimator.ofFloat(iv, "translationX",-100,100);
    oa2 = ObjectAnimator.ofFloat(iv,"scaleX",1f,0.5f);
    oa3 = ObjectAnimator.ofFloat(iv,"rotation",0,45);
     oa4 = ObjectAnimator.ofFloat(iv,"alpha",1f,0.4f);
     oa.start();

//使用Animation集合
        AnimatorSet set = new AnimatorSet();
        //oa1,oa2,oa3,oa4:不同的Animation动画变换法则,一起使用
        set.playSequentially(oa1,oa2,oa3,oa4);//设置变换法则
        set.setTarget(iv);//设置变换对象
        set.start();

2.Paint画笔工具,(Canvas(画板的画笔))

Paint的一些常用属性 去·
setARGB(int a,int r,int g,int b);设置颜色(value 0~255)
setAntiAlias(boolean aa)是否抗锯齿
setColor(int color)设置颜色
setPathEffect(PathEffect path)绘制路径的路径效果
......

代码来自:疯狂Android讲义

public class MyView extends View
{
    public MyView(Context context, AttributeSet set)
    {
        super(context, set);
    }
    @Override
    // 重写该方法,进行绘图
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);
        // 把整张画布绘制成白色
        canvas.drawColor(Color.WHITE);
        Paint paint = new Paint();
        // 去锯齿
        paint.setAntiAlias(true);
        paint.setColor(Color.BLUE);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(4);
        int viewWidth = this.getWidth();
        // 绘制圆形
        canvas.drawCircle(viewWidth / 10 + 10, viewWidth / 10 + 10
            , viewWidth / 10, paint);
        // 绘制正方形
        canvas.drawRect(10 , viewWidth / 5 + 20 , viewWidth / 5 + 10
            , viewWidth * 2 / 5 + 20 , paint);
        // 绘制矩形
        canvas.drawRect(10, viewWidth * 2 / 5 + 30, viewWidth / 5 + 10
            , viewWidth / 2 + 30, paint);
        RectF re1 = new RectF(10, viewWidth / 2 + 40
            , 10 + viewWidth / 5 ,viewWidth * 3 / 5 + 40);
        // 绘制圆角矩形
        canvas.drawRoundRect(re1, 15, 15, paint);
        RectF re11 = new RectF(10, viewWidth * 3 / 5 + 50
            , 10 + viewWidth / 5 ,viewWidth * 7 / 10 + 50);
        // 绘制椭圆
        canvas.drawOval(re11, paint);
        // 定义一个Path对象,封闭成一个三角形
        Path path1 = new Path();
        path1.moveTo(10, viewWidth * 9 / 10 + 60);
        path1.lineTo(viewWidth / 5 + 10, viewWidth * 9 / 10 + 60);
        path1.lineTo(viewWidth / 10 + 10, viewWidth * 7 / 10 + 60);
        path1.close();
        // 根据Path进行绘制,绘制三角形
        canvas.drawPath(path1, paint);
        // 定义一个Path对象,封闭成一个五角形
        Path path2 = new Path();
        path2.moveTo(10 + viewWidth / 15, viewWidth * 9 / 10 + 70);
        path2.lineTo(10 + viewWidth * 2 / 15, viewWidth * 9 / 10 + 70);
        path2.lineTo(10 + viewWidth / 5, viewWidth + 70);
        path2.lineTo(10 + viewWidth / 10, viewWidth * 11/10 + 70);
        path2.lineTo(10 , viewWidth + 70);
        path2.close();
        // 根据Path进行绘制,绘制五角形
        canvas.drawPath(path2, paint);
        // ----------设置填充风格后绘制----------
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.RED);
        // 绘制圆形
        canvas.drawCircle(viewWidth * 3 / 10 + 20, viewWidth / 10 + 10
            , viewWidth / 10, paint);
        // 绘制正方形
        canvas.drawRect(viewWidth / 5 + 20 , viewWidth / 5 + 20
            , viewWidth * 2 / 5 + 20 , viewWidth * 2 / 5 + 20 , paint);
        // 绘制矩形
        canvas.drawRect(viewWidth / 5 + 20, viewWidth * 2 / 5 + 30
            , viewWidth * 2 / 5 + 20 , viewWidth / 2 + 30, paint);
        RectF re2 = new RectF(viewWidth / 5 + 20, viewWidth / 2 + 40
            , 20 + viewWidth * 2 / 5 ,viewWidth * 3 / 5 + 40);
        // 绘制圆角矩形
        canvas.drawRoundRect(re2, 15, 15, paint);
        RectF re21 = new RectF(20 + viewWidth / 5, viewWidth * 3 / 5 + 50
            , 20 + viewWidth * 2 / 5 ,viewWidth * 7 / 10 + 50);
        // 绘制椭圆
        canvas.drawOval(re21, paint);
        // 定义一个Path对象,封闭成一个三角形
        Path path3 = new Path();
        path3.moveTo(20 + viewWidth / 5, viewWidth * 9 / 10 + 60);
        path3.lineTo(viewWidth * 2 / 5 + 20, viewWidth * 9 / 10 + 60);
        path3.lineTo(viewWidth * 3 / 10 + 20, viewWidth * 7 / 10 + 60);
        path3.close();
        // 根据Path进行绘制,绘制三角形
        canvas.drawPath(path3, paint);
        // 定义一个Path对象,封闭成一个五角形
        Path path4 = new Path();
        path4.moveTo(20 + viewWidth *4 / 15, viewWidth * 9 / 10 + 70);
        path4.lineTo(20 + viewWidth / 3, viewWidth * 9 / 10 + 70);
        path4.lineTo(20 + viewWidth * 2 / 5, viewWidth + 70);
        path4.lineTo(20 + viewWidth * 3 / 10, viewWidth * 11/10 + 70);
        path4.lineTo(20 + viewWidth / 5 , viewWidth + 70);
        path4.close();
        // 根据Path进行绘制,绘制五角形
        canvas.drawPath(path4, paint);
        // ----------设置渐变器后绘制----------
        // 为Paint设置渐变器
        Shader mShader = new LinearGradient(0, 0, 40, 60
            , new int[] {Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW }
            , null , Shader.TileMode.REPEAT);
        paint.setShader(mShader);
        //设置阴影
        paint.setShadowLayer(25 , 20 , 20 , Color.GRAY);
        // 绘制圆形
        canvas.drawCircle(viewWidth / 2 + 30, viewWidth / 10 + 10
            , viewWidth / 10, paint);
        // 绘制正方形
        canvas.drawRect(viewWidth * 2 / 5 + 30 , viewWidth / 5 + 20
            , viewWidth * 3 / 5 + 30 , viewWidth * 2 / 5 + 20 , paint);
        // 绘制矩形
        canvas.drawRect(viewWidth * 2 / 5 + 30, viewWidth * 2 / 5 + 30
            , viewWidth * 3 / 5 + 30 , viewWidth / 2 + 30, paint);
        RectF re3 = new RectF(viewWidth * 2 / 5 + 30, viewWidth / 2 + 40
            , 30 + viewWidth * 3 / 5 ,viewWidth * 3 / 5 + 40);
        // 绘制圆角矩形
        canvas.drawRoundRect(re3, 15, 15, paint);
        RectF re31 = new RectF(30 + viewWidth *2 / 5, viewWidth * 3 / 5 + 50
            , 30 + viewWidth * 3 / 5 ,viewWidth * 7 / 10 + 50);
        // 绘制椭圆
        canvas.drawOval(re31, paint);
        // 定义一个Path对象,封闭成一个三角形
        Path path5 = new Path();
        path5.moveTo(30 + viewWidth * 2/ 5, viewWidth * 9 / 10 + 60);
        path5.lineTo(viewWidth * 3 / 5 + 30, viewWidth * 9 / 10 + 60);
        path5.lineTo(viewWidth / 2 + 30, viewWidth * 7 / 10 + 60);
        path5.close();
        // 根据Path进行绘制,绘制三角形
        canvas.drawPath(path5, paint);
        // 定义一个Path对象,封闭成一个五角形
        Path path6 = new Path();
        path6.moveTo(30 + viewWidth * 7 / 15, viewWidth * 9 / 10 + 70);
        path6.lineTo(30 + viewWidth * 8 / 15, viewWidth * 9 / 10 + 70);
        path6.lineTo(30 + viewWidth * 3 / 5, viewWidth + 70);
        path6.lineTo(30 + viewWidth / 2, viewWidth * 11/10 + 70);
        path6.lineTo(30 + viewWidth * 2 / 5 , viewWidth + 70);
        path6.close();
        // 根据Path进行绘制,绘制五角形
        canvas.drawPath(path6, paint);
        // ----------设置字符大小后绘制----------
        paint.setTextSize(48);
        paint.setShader(null);
        // 绘制7个字符串
        canvas.drawText(getResources().getString(R.string.circle)
            , 60 + viewWidth * 3 / 5, viewWidth / 10 + 10, paint);
        canvas.drawText(getResources().getString(R.string.square)
            , 60 + viewWidth * 3 / 5, viewWidth * 3 / 10 + 20, paint);
        canvas.drawText(getResources().getString(R.string.rect)
            , 60 + viewWidth * 3 / 5, viewWidth * 1 / 2 + 20, paint);
        canvas.drawText(getResources().getString(R.string.round_rect)
            , 60 + viewWidth * 3 / 5, viewWidth * 3 / 5 + 30, paint);
        canvas.drawText(getResources().getString(R.string.oval)
            , 60 + viewWidth * 3 / 5, viewWidth * 7 / 10 + 30, paint);
        canvas.drawText(getResources().getString(R.string.triangle)
            , 60 + viewWidth * 3 / 5, viewWidth * 9 / 10 + 30, paint);
        canvas.drawText(getResources().getString(R.string.pentagon)
            , 60 + viewWidth * 3 / 5, viewWidth * 11 / 10 + 30, paint);
    }
3.使用DrawBitmapMesh扭曲图像
Canvas提供了一个
drawBitmapMesh(Bitmap bitmap,int meshWidth,int meshHeight,float[] verts,int vertOffset,int[] colors,int colorOffset,Paint pain);
drawBitmapMesh()方法的关键参数如下
>bitmap:制定需要扭曲的源位图
>meshWidth:该参数控制在横向上把资源位图划分成多少小格
>meshHeight:该参数控制在纵向上把资源位图划分成多少格
>verts:该参数是一个长度为(meshWidth+1)*(meshHeight+1)*2的叔祖,记录了扭曲后的个位图的顶点,虽然是一维数组,它的计数方式如下(x0,y0)(x1,y1)....(xN,yN)
>vertOffset:控制Verts数组中第几个数组开始扭曲(忽略之前的数据)
>
//代码来自:疯狂Android讲义
/*
该方法利用drawBitmapMesh方法进行图片的扭曲
当用户触摸到指定点时,指定点将会背扭曲
*/
public class MainActivity extends Activity
{
    private Bitmap bitmap;
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this, R.drawable.jinta));
    }
    private class MyView extends View
    {
        // 定义两个常量,这两个常量指定该图片横向、纵向上都被划分为20格
        private final int WIDTH = 20;
        private final int HEIGHT = 20;
        // 记录该图片上包含441个顶点
        private final int COUNT = (WIDTH + 1) * (HEIGHT + 1);
        // 定义一个数组,保存Bitmap上的21 * 21个点的坐标
        private final float[] verts = new float[COUNT * 2];
        // 定义一个数组,记录Bitmap上的21 * 21个点经过扭曲后的坐标
        // 对图片进行扭曲的关键就是修改该数组里元素的值
        private final float[] orig = new float[COUNT * 2];
        public MyView(Context context, int drawableId)
        {
            super(context);
            setFocusable(true);
            // 根据指定资源加载图片
            bitmap = BitmapFactory.decodeResource(getResources()
                    , drawableId);
            // 获取图片宽度、高度
            float bitmapWidth = bitmap.getWidth();
            float bitmapHeight = bitmap.getHeight();
            int index = 0;
            for (int y = 0; y <= HEIGHT; y++)
            {
                float fy = bitmapHeight * y / HEIGHT;
                for (int x = 0; x <= WIDTH; x++)
                {
                    float fx = bitmapWidth * x / WIDTH;
                    // 初始化orig、verts数组。 初始化后,orig、verts
                    // 两个数组均匀地保存了21 * 21个点的x,y坐标
                    orig[index * 2 + 0] = verts[index * 2 + 0] = fx;
                    orig[index * 2 + 1] = verts[index * 2 + 1] = fy;
                    index += 1;
                }
            }
            // 设置背景色
            setBackgroundColor(Color.WHITE);
        }
        @Override
        protected void onDraw(Canvas canvas)
        {
            //对bitmap按verts数组进行扭曲
            //从第一个点(由第5个参数0控制)开始扭曲
            canvas.drawBitmapMesh(bitmap, WIDTH, HEIGHT, verts
                    , 0, null, 0,null);
        }
        // 工具方法,用于根据触摸事件的位置计算verts数组里各元素的值
        private void warp(float cx, float cy)
        {
            for (int i = 0; i < COUNT * 2; i += 2)
            {
                float dx = cx - orig[i + 0];
                float dy = cy - orig[i + 1];
                float dd = dx * dx + dy * dy;
                // 计算每个坐标点与当前点(cx、cy)之间的距离
                float d = (float) Math.sqrt(dd);
                // 计算扭曲度,距离当前点(cx、cy)越远,扭曲度越小
                float pull = 100000 / ((float) (dd * d));
                // 对verts数组(保存bitmap上21 * 21个点经过扭曲后的坐标)重新赋值
                if (pull >= 1)
                {
                    verts[i + 0] = cx;
                    verts[i + 1] = cy;
                }
                else
                {
                    // 控制各顶点向触摸事件发生点偏移
                    verts[i + 0] = orig[i + 0] + dx * pull;
                    verts[i + 1] = orig[i + 1] + dy * pull;
                }
            }
            // 通知View组件重绘
            invalidate();
        }
        @Override
        public boolean onTouchEvent(MotionEvent event)
        {
            // 调用warp方法根据触摸屏事件的坐标点来扭曲verts数组
            warp(event.getX(), event.getY());
            return true;
        }
    }
4.使用Shader填充图形
》》Shader类包含了一个setShader(Shader s)方法,该方法控制“Paint画笔”的渲染效果,就像PhotoShop中的渲染类似

Shader是一个抽象类,有以下实现类
>BitmapShader:使用位图平铺的渲染效果
>LinearGradient:使用线性渐变填充图形
>ReadialGradient:使用圆形渐变来填充图形
>SweepGradient:实用角度变换来填充图形
>ComposeShader:使用组合渲染效果来填充图形
public class MainActivity extends Activity
        implements OnClickListener
{
    // 声明位图渲染对象
    private Shader[] shaders = new Shader[5];
    // 声明颜色数组
    private int[] colors;
    MyView myView;
    // 自定义视图类
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        myView = (MyView)findViewById(R.id.my_view);
        // 获得Bitmap实例
        Bitmap bm = BitmapFactory.decodeResource(getResources()
                , R.drawable.water);
        // 设置渐变的颜色组,也就是按红、绿、蓝的方式渐变
        colors = new int[] { Color.RED, Color.GREEN, Color.BLUE };
        // 实例化BitmapShader,x坐标方向重复图形,y坐标方向镜像图形
        shaders[0] = new BitmapShader(bm, TileMode.REPEAT,
                TileMode.MIRROR);
        // 实例化LinearGradient
        shaders[1] = new LinearGradient(0, 0, 100, 100
                , colors, null, TileMode.REPEAT);
        // 实例化RadialGradient
        shaders[2] = new RadialGradient(100, 100, 80, colors, null,
                TileMode.REPEAT);
        // 实例化SweepGradient
        shaders[3] = new SweepGradient(160, 160, colors, null);
        // 实例化ComposeShader
        shaders[4] = new ComposeShader(shaders[1], shaders[2],
                PorterDuff.Mode.DARKEN);
        Button bn1 = (Button)findViewById(R.id.bn1);
        Button bn2 = (Button)findViewById(R.id.bn2);
        Button bn3 = (Button)findViewById(R.id.bn3);
        Button bn4 = (Button)findViewById(R.id.bn4);
        Button bn5 = (Button)findViewById(R.id.bn5);
        bn1.setOnClickListener(this);
        bn2.setOnClickListener(this);
        bn3.setOnClickListener(this);
        bn4.setOnClickListener(this);
        bn5.setOnClickListener(this);
    }
    @Override
    public void onClick(View source)
    {
        switch(source.getId())
        {
            case R.id.bn1:
                myView.paint.setShader(shaders[0]);
                break;
            case R.id.bn2:
                myView.paint.setShader(shaders[1]);
                break;
            case R.id.bn3:
                myView.paint.setShader(shaders[2]);
                break;
            case R.id.bn4:
                myView.paint.setShader(shaders[3]);
                break;
            case R.id.bn5:
                myView.paint.setShader(shaders[4]);
                break;
        }
        // 重绘界面
        myView.invalidate();
    }
}
4.使用SurfaceView的绘图机制
>使用View绘图的缺陷,
>缺乏双缓冲机制
>更新View必须重绘整张图片

由于View的以上缺陷,SurfaceView更加出色,在绘制游戏动画方面一般用SurfaceView
SurfaceView一般与SurfaceHolder结合使用
SurfaceView的getHolder()即可获得与SurfaceView关联的SurfaceHolder
SurfaceHolder常用方法获取Canvas
>Canvas lockCanvas(),锁定整个SurfaceView对象,获取SurfaceView上的Canvas
>Canvas lockCanvas(Rect dirty)锁定SurfaceView上的Rect区域,仅仅对这个区域进行更新
>unlockCanvasAndPost(canvas)//提交并释放Canvas

因为Surface对于普通开发者并不常用,下面就不贴代码了,

3.path类>

    Path可以预先在View上将N个点连接成一条路径然后调用Canvas的drawPath(path,paint)方法,绘制一条图形,Android还为路径绘制提供了PathEffect类它包含了以下子类
>ComposePathEffect
>CornerPathEffect
>DashPathEffect
>DiscretePathEffect
>SumPathEffect

CornerPathEffect:
这个类的作用就是将Path的各个连接线段之间的夹角用一种更平滑的方式连接,类似于圆弧与切线的效果。一般的,通过CornerPathEffect(float radius)指定一个具体的圆弧半径来实例化一个CornerPathEffect。

    DashPathEffect:

    这个类的作用就是将Path的线段虚线化。
    构造函数为DashPathEffect(float[] intervals, float offset),其中intervals为虚线的ON和OFF数组,该数组的length必须大于等于2,phase为绘制时的偏移量。

    DiscretePathEffect:

    这个类的作用是打散Path的线段,使得在原来路径的基础上发生打散效果。
    一般的,通过构造DiscretePathEffect(float segmentLength,float deviation)来构造一个实例,其中,segmentLength指定最大的段长,deviation指定偏离量。

    PathDashPathEffect:

    这个类的作用是使用Path图形来填充当前的路径,其构造函数为PathDashPathEffect (Path shape, float advance, float phase,PathDashPathEffect.Stylestyle)。
    shape则是指填充图形,advance指每个图形间的间距,phase为绘制时的偏移量,style为该类自由的枚举值,有三种情况:Style.ROTATE、Style.MORPH和
    Style.TRANSLATE。其中ROTATE的情况下,线段连接处的图形转换以旋转到与下一段移动方向相一致的角度进行转转,MORPH时图形会以发生拉伸或压缩等变形的情况与下一段相连接,TRANSLATE时,图形会以位置平移的方式与下一段相连接。

    ComposePathEffect:

    组合效果,这个类需要两个PathEffect参数来构造一个实例,ComposePathEffect (PathEffect outerpe,PathEffect innerpe),表现时,会首先将innerpe表现出来,然后再在innerpe的基础上去增加outerpe的效果。

    SumPathEffect:

    叠加效果,这个类也需要两个PathEffect作为参数SumPathEffect(PathEffect first,PathEffect second),但与ComposePathEffect不同的是,在表现时,会分别对两个参数的效果各自独立进行表现,然后将两个效果简单的重叠在一起显示出来。
Path path = new Path();
path.moveTo(int x,int y);//将坐标移到点(x,y)
path.lineTo(int x,int y);//绘制路径
path.lineTo(int x,int y);
path.close();
canvas.drawPath(Path path,Paint paint);//将路径绘制到Canvas上

代码来自:疯狂Android讲义

public class MainActivity extends Activity
{
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
    class MyView extends View
    {
        float phase;
        PathEffect[] effects = new PathEffect[7];
        int[] colors;
        private Paint paint;
        Path path;
        public MyView(Context context)
        {
            super(context);
            paint = new Paint();
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeWidth(4);
            // 创建并初始化Path
            path = new Path();
            path.moveTo(0, 0);
            for (int i = 1; i <= 40; i++)
            {
                // 生成40个点,随机生成它们的Y坐标,并将它们连成一条Path
                path.lineTo(i * 20, (float) Math.random() * 60);
            }
            // 初始化7个颜色
            colors = new int[] { Color.BLACK, Color.BLUE, Color.CYAN,
                Color.GREEN, Color.MAGENTA, Color.RED, Color.YELLOW };
        }
        @Override
        protected void onDraw(Canvas canvas)
        {
            // 将背景填充成白色
            canvas.drawColor(Color.WHITE);
            // -----------下面开始初始化7种路径效果----------
            // 不使用路径效果
            effects[0] = null;
            // 使用CornerPathEffect路径效果
            effects[1] = new CornerPathEffect(10);
            // 初始化DiscretePathEffect
            effects[2] = new DiscretePathEffect(3.0f, 5.0f);
            // 初始化DashPathEffect
            effects[3] = new DashPathEffect(new float[] { 20, 10, 5, 10 },
                    phase);
            // 初始化PathDashPathEffect
            Path p = new Path();
            p.addRect(0, 0, 8, 8, Path.Direction.CCW);
            effects[4] = new PathDashPathEffect(p, 12, phase,
                    PathDashPathEffect.Style.ROTATE);
            // 初始化ComposePathEffect
            effects[5] = new ComposePathEffect(effects[2], effects[4]);
            effects[6] = new SumPathEffect(effects[4], effects[3]);
            // 将画布移动到(8、8)处开始绘制
            canvas.translate(8, 8);
            // 依次使用7种不同路径效果、7种不同的颜色来绘制路径
            for (int i = 0; i < effects.length; i++)
            {
                paint.setPathEffect(effects[i]);
                paint.setColor(colors[i]);
                canvas.drawPath(path, paint);
                canvas.translate(0, 60);
            }
            // 改变phase值,形成动画效果
            phase += 1;
            invalidate();
        }
    }
时间: 2024-11-03 22:25:59

Android Animation (动画设计)的相关文章

Android Animation 动画Demo(Frame逐帧动画)

上一篇介绍了Animation动画其一:Tween补间动画. 这篇文章接下来介绍Animation另一种动画形式:Frame逐帧动画. Frame动画是一系列图片按照一定的顺序展示的过程,和放电影的机制很相似,我们称为逐帧动画.Frame动画可以被定义在XML文件中,也可以完全编码实现(后面会给出这两种实现方式的源代码Demo). 下面分别介绍: 一.定义在xml中实现: 实现效果图: 源代码: 布局文件:main.xml: <?xml version="1.0" encodin

Android Animation动画(很详细)

http://www.360doc.com/content/13/0102/22/6541311_257754535.shtml Android Animation动画(很详细),布布扣,bubuko.com

Android Animation动画详解(二): 组合动画特效

前言 上一篇博客Android Animation动画详解(一): 补间动画 我已经为大家介绍了Android补间动画的四种形式,相信读过该博客的兄弟们一起都了解了.如果你还不了解,那点链接过去研读一番,然后再过来跟着我一起学习如何把简单的动画效果组合在一起,做出比较酷炫的动画特效吧. 一. 动画的续播 如题,大家想想,如果一个页面上包含了许多动画,这些动画要求按顺序播放,即一个动画播放完成后,继续播放另一个动画,使得这些动画具有连贯性.那该如何实现呢? 有开发经验或者是逻辑思维的人肯定会想,对

Android Animation 动画

动画类型 Android的animation由四种类型组成  Android动画模式 Animation主要有两种动画模式:一种是tweened animation(渐变动画) XML中 JavaCode alpha AlphaAnimation scale ScaleAnimation 一种是frame by frame(画面转换动画) XML中 JavaCode translate TranslateAnimation rotate RotateAnimation 如何在XML文件中定义动画

Android Animation动画实战(一): 从布局动画引入ListView滑动时,每一Item项的显示动画

前言: 之前,我已经写了两篇博文,给大家介绍了Android的基础动画是如何实现的,如果还不清楚的,可以点击查看:Android Animation动画详解(一): 补间动画 及 Android Animation动画详解(二): 组合动画特效 . 已经熟悉了基础动画的实现后,便可以试着去实现常见APP中出现过的那些精美的动画.今天我主要给大家引入一个APP的ListView的动画效果: 当展示ListView时,Listview的每一个列表项都按照规定的动画显示出来. 说起来比较抽象,先给大家

Android Animation 动画属性

在 Android 中, Animation 动画效果的实现可以通过两种方式进行实现: 一种是 tweened animation 渐变动画,另一种是 frame by frame animation 补间(画面转换)动画. tweened animation 渐变动画有以下两种类型: 1.alpha   渐变透明度动画效果 2.scale   渐变尺寸伸缩动画效果 frame by frame animation 画面转换动画有以下两种类型: 1.translate  画面转换位置移动动画效果

Android Animation 动画Demo

本文主要介绍Android中的Animation动画. Android提供了2中动画:Tween动画和Frame动画. 本文中主要讲解Tween动画,下篇文章中会讲到Frame动画. Tween动画: 通过对View的内容进行一系列的图形变换(包括平移,缩放,旋转,改变透明度)来实现动画的效果,动画效果的定义可以采用XML方式也可以采用编码来做Tween动画(文章最后会给出两种方式动画的源代码Demo). 动画的类型 Xml定义动画使用的配置节点 编码定义动画使用的类 渐变透明度动画效果(简称透

Android Animation动画的xml使用

在Android应用程序,使用动画效果,能带给用户更好的感觉,做动画可以通过XML或Android代码来实现. Animation动画效果的实现可以通过两种方式进行实现,一种是tweened animation (渐变动画),另一种是frame by frame animation (画面转换动画). tweened animation渐变动画有以下两种类型: 1.alpha     渐变透明度动画效果 2.scale    渐变尺寸伸缩动画效果 frame by frame animation

android animation动画效果的两种实现方式

animation动画效果两种实现方式 注:此例为AlphaAnimation效果,至于其他效果,换一下对象即可. 1..java文件 代码控制 添加并且开始animation动画 //添加动画效果 AlphaAnimation animation = new AlphaAnimation(0.3f, 1.0f); //设置次效果的持续时间 animation.setDuration(2000); //设置动画的监听事件 animation.setAnimationListener(new An