首页 > 程序开发 > 移动开发 > Android >

Android Animation (动画设计)

2017-07-14

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动画文件


    
    
    


//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);//开始


    
    
        
        
    


//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();
        }
    }
相关文章
最新文章
热点推荐