逐帧动画:
补间动画
结合动画
自定义动画
属性动画一
属性动画二
动画三
动画四

      • 逐帧动画
        • 语法格式
          • MainActivity代码
      • 补间动画Tween
        • Animation子类
        • interpolator简单理解
          • 代码
        • 结合动画
          • MainActivity代码
        • 自定义补间动画
          • MyAnimation代码
          • MainActivity代码
          • activity_mainxml
      • 属性动画
        • 定义属性动画的方法
        • 使用属性动画的步骤
        • 属性动画和补间动画的区别
        • 属性动画的API
        • 属性动画一
          • ShapeHolder代码
          • MainActivity代码
        • 属性动画二
          • ShapeHolder代码
          • MainActivity代码
      • 使用SurfaceView实现动画
        • 使用自定义View绘制图片的 缺陷
        • 动画三
          • FishView代码
        • 动画四
          • MainActivity代码

逐帧动画

定义逐帧动画,只要在;元素中使用子元素定义动画的全部帧就可以了!

语法格式:

<?xml version="1.0" encoding="utf-8"?><animation-list xmlns:android="http://schemas.android.com/apk/res/android"    android:oneshot="false">        <item android:drawable="图片" android:duration="60" />    animation-list >

MainActivity代码:

public class MainActivity extends Activity{    private MyView myView;    private AnimationDrawable anim;    private MediaPlayer bomb;    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        requestWindowFeature(Window.FEATURE_NO_TITLE);        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);        // 使用FrameLayout布局管理器,它允许组件自己控制位置        FrameLayout frame = new FrameLayout(this);        setContentView(frame);        // 设置使用背景        frame.setBackgroundResource(R.drawable.back);        // 加载音效        bomb = MediaPlayer.create(this, R.raw.bomb);        myView = new MyView(this);        // 设置myView用于显示blast动画        myView.setBackgroundResource(R.anim.blast);        // 设置myView默认为隐藏        myView.setVisibility(View.INVISIBLE);        // 获取动画对象        anim = (AnimationDrawable) myView.getBackground();        frame.addView(myView);        frame.setOnTouchListener(new OnTouchListener()        {            @Override            public boolean onTouch(View source, MotionEvent event)            {                // 只处理按下事件(避免每次产生两个动画效果)                if (event.getAction() == MotionEvent.ACTION_DOWN)                {                    // 先停止动画播放                    anim.stop();                    float x = event.getX();                    float y = event.getY();                    // 控制myView的显示位置                    myView.setLocation((int) y - 40, (int) x - 20);                    myView.setVisibility(View.VISIBLE);                    // 启动动画                    anim.start();                    // 播放音效                    bomb.start();                }                return false;            }        });    }    // 定义一个自定义View,该自定义View用于播放“爆炸”效果    class MyView extends ImageView    {        public MyView(Context context)        {            super(context);        }        // 定义一个方法,该方法用于控制MyView的显示位置        public void setLocation(int top, int left)        {            this.setFrame(left-100, top-100, left + 100, top + 100);        }        // 重写该方法,控制如果动画播放到最后一帧时,隐藏该View        @Override        protected void onDraw(Canvas canvas) // ①        {            try            {                Field field = AnimationDrawable.class                        .getDeclaredField("mCurFrame");                field.setAccessible(true);                // 获取anim动画的当前帧                int curFrame = field.getInt(anim);                // 如果已经到了最后一帧                if (curFrame == anim.getNumberOfFrames() - 1)                {                    // 让该View隐藏                    setVisibility(View.INVISIBLE);                }            }            catch (Exception e)            {            }            super.onDraw(canvas);        }    }}

补间动画(Tween)

资源定义完成后,可以使用AnimationUtils工具类加载指定的动画资源。

Animation子类:

  1. AlphaAnimation:
  2. ScaleAnimation:
  3. TranslateAnimation:
  4. RotateAnimation:

interpolator简单理解

interpolator:根据特定的算法计算出整个动画所需要动态插入帧的密度和位置。负责控制动画的变化速度。使其动画效果更流畅。

代码

public class MainActivity extends Activity{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        final ImageView flower = (ImageView)                findViewById(R.id.flower);        // 加载第一份动画资源        final Animation anim = AnimationUtils                .loadAnimation(this, R.anim.anim);        // 设置动画结束后保留结束状态        anim.setFillAfter(true);        // 加载第二份动画资源        final Animation reverse = AnimationUtils.loadAnimation(this                , R.anim.reverse);        // 设置动画结束后保留结束状态        reverse.setFillAfter(true);        Button bn = (Button) findViewById(R.id.bn);        final Handler handler = new Handler()        {            @Override            public void handleMessage(Message msg)            {                if (msg.what == 0x123)                {                    flower.startAnimation(reverse);                }            }        };        bn.setOnClickListener(new OnClickListener()        {            @Override            public void onClick(View arg0)            {                flower.startAnimation(anim);                // 设置3.5秒后启动第二个动画                new Timer().schedule(new TimerTask()                {                    @Override                    public void run()                    {                        handler.sendEmptyMessage(0x123);                    }                }, 3500);            }        });    }}

结合动画

MainActivity代码:

public class MainActivity extends Activity{    // 记录蝴蝶ImageView当前的位置    private float curX = 0;    private float curY = 30;    // 记录蝴蝶ImageView下一个位置的坐标    float nextX = 0;    float nextY = 0;    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        // 获取显示蝴蝶的ImageView组件        final ImageView imageView = (ImageView)                findViewById(R.id.butterfly);        final Handler handler = new Handler()        {            @Override            public void handleMessage(Message msg)            {                if (msg.what == 0x123)                {                    // 横向上一直向右飞                    if (nextX > 320)                    {                        curX = nextX = 0;                    }                    else                    {                        nextX += 8;                    }                    // 纵向上可以随机上下                    nextY = curY + (float) (Math.random() * 10 - 5);                    // 设置显示蝴蝶的ImageView发生位移改变                    TranslateAnimation anim = new TranslateAnimation(                            curX, nextX, curY, nextY);                    curX = nextX;                    curY = nextY;                    anim.setDuration(200);                    // 开始位移动画                    imageView.startAnimation(anim); // ①                }            }        };        final AnimationDrawable butterfly = (AnimationDrawable)                imageView.getBackground();        imageView.setOnClickListener(new OnClickListener()        {            @Override            public void onClick(View v)            {                // 开始播放蝴蝶振翅的逐帧动画                butterfly.start();  // ②                // 通过定制器控制每0.2秒运行一                // 次TranslateAnimation动画                new Timer().schedule(new TimerTask()                {                    @Override                    public void run()                    {                        handler.sendEmptyMessage(0x123);                    }                }, 0, 200);            }        });    }}

自定义补间动画:

自定义补间动画需要继承Animation,重写抽象方法applyTransformation(float interpolatedTime,Transformation t)方法,参数说明:

  1. interpolatedTime:代表动画的时间进行比,无论动画实际的持续时间如何,当动画播放时,该参数总是从0变化到1
  2. Transformation:代表补间动画在不同时刻对图形或者组件的变形程度

Camera常用方法如下:

  1. getMatrix(Matrix matrix):将Camera所做的变换应用到指定matrix上。

  2. rotateX(float deg):使目标组件沿X轴旋转。

  3. rotateY(float deg):使目标组件沿Y轴旋转。

  4. rotateZ(float deg):使目标组件沿Z轴旋转。

  5. translate(float x,float y,float z):使目标组件在三维空间里进行位移变换

  6. applyToCanvas(Canvas canvas):把Camera所做的变换应用到Canvas上。

MyAnimation代码:

public class MyAnimation extends Animation{    private float centerX;    private float centerY;    // 定义动画的持续事件    private int duration;    private Camera camera = new Camera();    public MyAnimation(float x, float y, int duration)    {        this.centerX = x;        this.centerY = y;        this.duration = duration;    }    @Override    public void initialize(int width, int height            , int parentWidth, int parentHeight)    {        super.initialize(width, height, parentWidth, parentHeight);        // 设置动画的持续时间        setDuration(duration);        // 设置动画结束后效果保留        setFillAfter(true);        setInterpolator(new LinearInterpolator());    }    /*     * 该方法的interpolatedTime代表了抽象的动画持续时间,不管动画实际持续时间多长,     * interpolatedTime参数总是从0(动画开始时)~1(动画结束时)     * Transformation参数代表了对目标组件所做的改变.     */    @Override    protected void applyTransformation(float interpolatedTime            , Transformation t)    {        camera.save();        // 根据interpolatedTime时间来控制X、Y、Z上的偏移        camera.translate(100.0f - 100.0f * interpolatedTime,                150.0f * interpolatedTime - 150,                80.0f - 80.0f * interpolatedTime);        // 设置根据interpolatedTime时间在Y轴上旋转不同角度        camera.rotateY(360 * (interpolatedTime));        // 设置根据interpolatedTime时间在X轴上旋转不同角度        camera.rotateX((360 * interpolatedTime));        // 获取Transformation参数的Matrix对象        Matrix matrix = t.getMatrix();        camera.getMatrix(matrix);        matrix.preTranslate(-centerX, -centerY);        matrix.postTranslate(centerX, centerY);        camera.restore();    }}

MainActivity代码:

public class MainActivity extends Activity{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        // 获取ListView组件        ListView list = (ListView) findViewById(R.id.list);        WindowManager windowManager = (WindowManager)                getSystemService(WINDOW_SERVICE);        Display display = windowManager.getDefaultDisplay();        DisplayMetrics metrice = new DisplayMetrics();        // 获取屏幕的宽和高        display.getMetrics(metrice);        // 设置对ListView组件应用动画        list.setAnimation(new MyAnimation(metrice.xdpi / 2                , metrice.ydpi / 2, 3500));    }}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="match_parent"><ListView      android:id="@+id/list"    android:layout_width="match_parent"     android:layout_height="match_parent"     android:entries="@array/bookArray"    />LinearLayout>

属性动画

定义属性动画的方法:

  1. 使用ValurAnimator或者ObjectAnimator的静态工厂方法来创建动画
  2. 使用资源文件来定义动画

使用属性动画的步骤

  1. 创建ValurAniamtor或ObjectAnimator对象,即可从XML资源加载,也可以使用ValurAniamtor或ObjectAnimator的静态工厂方法创建
  2. 根据需要设置Animator属性值
  3. 如果需要监听Animator的改变事件,需要为Animator设置事件监听器
  4. 如果有多个动画需要按次序或者同时处理,则需要使用AnimatorSet组合这些动画
  5. 调用Animator的start()方法来启动。

    属性动画和补间动画的区别:

  6. 补间动画只能定义两个关键帧在“透明度
    ”“旋转”“缩放”“位移”4个方面变化。属性动画可以定义任何属性的变化

  7. 补间动画只对UI组件执行动画,但属性动画几乎可以对任何对象执行动画,不管是否显示在屏幕上

属性动画的API:

  1. Animator:它提供创建属性动画的基类,通常用于被继承并重写它的相关方法
  2. ValueAnimator:用于计算相关属性值
  3. ObjectAnimator:ValueAnimator的子类,允许程序员对指定对象的属性执行动画。
  4. AnimatorSet:Animator的子类,用于组合多个Animator,并指定多个Animator按次序播放还是同时播放。
  5. IntEvaluator:用于计算int类型的计算器
  6. FloatEvaluator:用于计算float类型属性值的计算器
  7. ArgbEvaluator:用于计算以十六进制形式表示的颜色值的计算器
  8. TypeEvaluator:计算器接口,开发者可以通过实现该接口来实现自定义计算器。

    属性动画一

    ShapeHolder代码:
public class ShapeHolder{    private float x = 0, y = 0;    private ShapeDrawable shape;    private int color;    private RadialGradient gradient;    private float alpha = 1f;    private Paint paint;    public ShapeHolder(ShapeDrawable s)    {        shape = s;    }    public float getX()    {        return x;    }    public void setX(float x)    {        this.x = x;    }    public float getY()    {        return y;    }    public void setY(float y)    {        this.y = y;    }    public ShapeDrawable getShape()    {        return shape;    }    public void setShape(ShapeDrawable shape)    {        this.shape = shape;    }    public int getColor()    {        return color;    }    public void setColor(int color)    {        this.color = color;    }    public RadialGradient getGradient()    {        return gradient;    }    public void setGradient(RadialGradient gradient)    {        this.gradient = gradient;    }    public float getAlpha()    {        return alpha;    }    public void setAlpha(float alpha)    {        this.alpha = alpha;    }    public Paint getPaint()    {        return paint;    }    public void setPaint(Paint paint)    {        this.paint = paint;    }}

MainActivity代码;

public class MainActivity extends Activity{    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        // 获取ListView组件        ListView list = (ListView) findViewById(R.id.list);        WindowManager windowManager = (WindowManager)                getSystemService(WINDOW_SERVICE);        Display display = windowManager.getDefaultDisplay();        DisplayMetrics metrice = new DisplayMetrics();        // 获取屏幕的宽和高        display.getMetrics(metrice);        // 设置对ListView组件应用动画        list.setAnimation(new MyAnimation(metrice.xdpi / 2                , metrice.ydpi / 2, 3500));    }}

属性动画二:

ShapeHolder代码:

同属性动画一中的ShapeHolder代码:

MainActivity代码:

public class MainActivity extends Activity{    // 定义小球的大小的常量    static final float BALL_SIZE = 50F;    // 定义小球从屏幕上方下落到屏幕底端的总时间    static final float FULL_TIME = 3000;    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        LinearLayout container = (LinearLayout)            findViewById(R.id.container);        // 设置该窗口显示MyAnimationView组件        container.addView(new MyAnimationView(this));    }    public class MyAnimationView extends View    {        public final ArrayList balls                = new ArrayList();        public MyAnimationView(Context context)        {            super(context);            // 加载动画资源            ObjectAnimator colorAnim = (ObjectAnimator) AnimatorInflater                .loadAnimator(MainActivity.this, R.animator.color_anim);            colorAnim.setEvaluator(new ArgbEvaluator());            // 对该View本身应用属性动画            colorAnim.setTarget(this);            // 开始指定动画            colorAnim.start();        }        @Override        public boolean onTouchEvent(MotionEvent event)        {            // 如果触碰事件不是按下、移动事件            if (event.getAction() != MotionEvent.ACTION_DOWN                && event.getAction() != MotionEvent.ACTION_MOVE)            {                return false;            }            //  在事件发生点添加一个小球(用一个圆形代表)            ShapeHolder newBall = addBall(event.getX(), event.getY());            // 计算小球下落动画开始时的y坐标            float startY = newBall.getY();            // 计算小球下落动画结束时的y坐标(落到屏幕最下方,就是屏幕高度减去小球高度)            float endY = getHeight() - BALL_SIZE;            // 获取屏幕高度            float h = (float) getHeight();            float eventY = event.getY();            // 计算动画的持续时间            int duration = (int) (FULL_TIME * ((h - eventY) / h));            // 定义小球“落下”的动画:            // 让newBall对象的y属性从事件发生点变化到屏幕最下方            ValueAnimator fallAnim = ObjectAnimator.ofFloat(                newBall, "y", startY, endY);            // 设置fallAnim动画的持续时间            fallAnim.setDuration(duration);            // 设置fallAnim动画的插值方式:加速插值            fallAnim.setInterpolator(new AccelerateInterpolator());            // 定义小球“压扁”的动画:该动画控制小球的x坐标“向左移”半个球            ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall                    , "x", newBall.getX(), newBall.getX() - BALL_SIZE / 2);            // 设置squashAnim1动画持续时间            squashAnim1.setDuration(duration / 4);            // 设置squashAnim1动画重复1次            squashAnim1.setRepeatCount(1);            // 设置squashAnim1动画的重复方式            squashAnim1.setRepeatMode(ValueAnimator.REVERSE);            // 设置squashAnim1动画的插值方式:减速插值            squashAnim1.setInterpolator(new DecelerateInterpolator());            // 定义小球“压扁”的动画:该动画控制小球的宽度加倍            ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall,                    "width", newBall.getWidth()                    , newBall.getWidth() + BALL_SIZE);            // 设置squashAnim2动画持续时间            squashAnim2.setDuration(duration / 4);            // 设置squashAnim2动画重复1次            squashAnim2.setRepeatCount(1);            // 设置squashAnim2动画的重复方式            squashAnim2.setRepeatMode(ValueAnimator.REVERSE);            // 设置squashAnim2动画的插值方式:减速插值            squashAnim2.setInterpolator(new DecelerateInterpolator());            // 定义小球“拉伸”的动画:该动画控制小球的y坐标“向下移”半个球            ObjectAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall                    , "y", endY, endY + BALL_SIZE / 2);            // 设置stretchAnim1动画持续时间            stretchAnim1.setDuration(duration / 4);            // 设置stretchAnim1动画重复1次            stretchAnim1.setRepeatCount(1);            // 设置stretchAnim1动画的重复方式            stretchAnim1.setRepeatMode(ValueAnimator.REVERSE);            // 设置stretchAnim1动画的插值方式:减速插值            stretchAnim1.setInterpolator(new DecelerateInterpolator());            // 定义小球“拉伸”的动画:该动画控制小球的高度减半            ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall,                    "height", newBall.getHeight()                    , newBall.getHeight() - BALL_SIZE / 2);            // 设置stretchAnim2动画持续时间            stretchAnim2.setDuration(duration / 4);            // 设置squashAnim2动画重复1次            stretchAnim2.setRepeatCount(1);            // 设置squashAnim2动画的重复方式            stretchAnim2.setRepeatMode(ValueAnimator.REVERSE);            // 设置squashAnim2动画的插值方式:减速插值            stretchAnim2.setInterpolator(new DecelerateInterpolator());            // 定义小球“弹起”的动画            ObjectAnimator bounceBackAnim = ObjectAnimator.ofFloat(                    newBall , "y", endY, startY);            // 设置持续时间            bounceBackAnim.setDuration(duration);            // 设置动画的插值方式:减速插值            bounceBackAnim.setInterpolator(new DecelerateInterpolator());            // 使用AnimatorSet按顺序播放“掉落/压扁&拉伸/弹起动画            AnimatorSet bouncer = new AnimatorSet();            // 定义在squashAnim1动画之前播放fallAnim下落动画            bouncer.play(fallAnim).before(squashAnim1);            // 由于小球在“屏幕”下方弹起时,小球要被压扁            // 即:宽度加倍、x坐标左移半个球,高度减半、y坐标下移半个球            // 因此此处指定播放squashAnim1的同时            // 还播放squashAnim2、stretchAnim1、stretchAnim2            bouncer.play(squashAnim1).with(squashAnim2);            bouncer.play(squashAnim1).with(stretchAnim1);            bouncer.play(squashAnim1).with(stretchAnim2);            // 指定播放stretchAnim2动画之后,播放bounceBackAnim弹起动画            bouncer.play(bounceBackAnim).after(stretchAnim2);            // 定义对newBall对象的alpha属性执行从1到0的动画(即定义渐隐动画)            ObjectAnimator fadeAnim = ObjectAnimator.ofFloat(newBall                    , "alpha", 1f, 0f);            // 设置动画持续时间            fadeAnim.setDuration(250);            // 为fadeAnim动画添加监听器            fadeAnim.addListener(new AnimatorListenerAdapter()            {                // 当动画结束时                @Override                public void onAnimationEnd(Animator animation)                {                    // 动画结束时将该动画关联的ShapeHolder删除                    balls.remove(((ObjectAnimator) animation).getTarget());                }            });            // 再次定义一个AnimatorSet来组合动画            AnimatorSet animatorSet = new AnimatorSet();            // 指定在播放fadeAnim之前,先播放bouncer动画            animatorSet.play(bouncer).before(fadeAnim);            // 开发播放动画            animatorSet.start();            return true;        }        private ShapeHolder addBall(float x, float y)        {            // 创建一个椭圆            OvalShape circle = new OvalShape();            // 设置该椭圆的宽、高            circle.resize(BALL_SIZE, BALL_SIZE);            // 将椭圆包装成Drawable对象            ShapeDrawable drawable = new ShapeDrawable(circle);            // 创建一个ShapeHolder对象            ShapeHolder shapeHolder = new ShapeHolder(drawable);            // 设置ShapeHolder的x、y坐标            shapeHolder.setX(x - BALL_SIZE / 2);            shapeHolder.setY(y - BALL_SIZE / 2);            int red = (int) (Math.random() * 255);            int green = (int) (Math.random() * 255);            int blue = (int) (Math.random() * 255);            // 将red、green、blue三个随机数组合成ARGB颜色            int color = 0xff000000 + red << 16 | green << 8 | blue;            // 获取drawable上关联的画笔            Paint paint = drawable.getPaint();            // 将red、green、blue三个随机数除以4得到商值组合成ARGB颜色            int darkColor = 0xff000000 | red / 4 << 16                | green / 4 << 8 | blue / 4;            // 创建圆形渐变            RadialGradient gradient = new RadialGradient(                37.5f, 12.5f, BALL_SIZE, color, darkColor                , Shader.TileMode.CLAMP);            paint.setShader(gradient);            // 为shapeHolder设置paint画笔            shapeHolder.setPaint(paint);            balls.add(shapeHolder);            return shapeHolder;        }        @Override        protected void onDraw(Canvas canvas)        {            // 遍历balls集合中的每个ShapeHolder对象            for (ShapeHolder shapeHolder : balls)            {                // 保存canvas的当前坐标系统                canvas.save();                // 坐标变换:将画布坐标系统平移到shapeHolder的X、Y坐标处                canvas.translate(shapeHolder.getX()                        , shapeHolder.getY());                // 将shapeHolder持有的圆形绘制在Canvas上                shapeHolder.getShape().draw(canvas);                // 恢复Canvas坐标系统                canvas.restore();            }        }    }}

使用SurfaceView实现动画

使用自定义View绘制图片的 缺陷

  1. View缺乏双缓冲机制
  2. 当程序需要更新View上的图片时,程序必须重新绘制View上显示的整张图片
  3. 新线程无法直接更新View组件

    动画三

    FishView代码:
public class FishView extends SurfaceView        implements SurfaceHolder.Callback{    private SurfaceHolder holder;    private UpdateViewThread updateThread;    private boolean hasSurface;    private Bitmap back;    private Bitmap[] fishs;    private int fishIndex = 0; // 定义变量记录绘制第几张鱼的图片    // 下面定义2个变量,记录鱼的初始位置    private float fishX = 778;    private float fishY = 500;    private float fishSpeed = 6; // 鱼的游动速度    // 定义鱼游动的角度    private int fishAngle = new Random().nextInt(60);    Matrix matrix = new Matrix();    public FishView(Context ctx, AttributeSet set)    {        super(ctx, set);        // 获取该SurfaceView对应的SurfaceHolder,并将该类的实例作为其Callback        holder = getHolder();        holder.addCallback(this);        hasSurface = false;        back = BitmapFactory.decodeResource(ctx.getResources()                , R.drawable.fishbg);        fishs = new Bitmap[10];        // 初始化鱼游动动画的10张图片        for(int i = 0 ; i < 10 ; i++)        {            try            {                int fishId = (Integer)R.drawable.class                        .getField("fish" + i).get(null);                fishs[i] = BitmapFactory.decodeResource(                        ctx.getResources(), fishId);            }            catch(Exception e){                e.printStackTrace();            }        }    }    public void resume()    {        // 创建和启动图像更新线程        if (updateThread == null)        {            updateThread = new UpdateViewThread();            if (hasSurface == true)                updateThread.start();        }    }    public void pause()    {        // 停止图像更新线程        if (updateThread != null)        {            updateThread.requestExitAndWait();            updateThread = null;        }    }    // 当SurfaceView被创建时回调该方法    @Override    public void surfaceCreated(SurfaceHolder holder)    {        hasSurface = true;        resume();    }    // 当SurfaceView将要被销毁时回调该方法    public void surfaceDestroyed(SurfaceHolder holder)    {        hasSurface = false;        pause();    }    // 当SurfaceView发生改变时回调该方法    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)    {        if (updateThread != null)            updateThread.onWindowResize(w, h);    }    class UpdateViewThread extends Thread    {        // 定义一个记录图形是否更新完成的旗标        private boolean done;        UpdateViewThread()        {            super();            done = false;        }        @Override        public void run()        {            SurfaceHolder surfaceHolder = holder;            // 重复绘图循环,直到线程停止            while (!done)            {                // 锁定SurfaceView,并返回到要绘图的Canvas                Canvas canvas = surfaceHolder.lockCanvas();  // ①                // 绘制背景图片                canvas.drawBitmap(back, 0, 0, null);                // 如果鱼“游出”屏幕之外,重新初始鱼的位置                if(fishX < 0)                {                    fishX = 778;                    fishY = 500;                    fishAngle = new Random().nextInt(60);                }                if(fishY < 0)                {                    fishX = 778;                    fishY = 500;                    fishAngle = new Random().nextInt(60);                }                // 使用Matrix来控制鱼的旋转角度和位置                matrix.reset();                matrix.setRotate(fishAngle);                matrix.postTranslate(fishX -= fishSpeed * Math                    .cos(Math.toRadians(fishAngle))                    , fishY -= fishSpeed * Math.sin(Math.toRadians(fishAngle)));                canvas.drawBitmap(fishs[fishIndex++ % fishs.length], matrix, null);                // 解锁Canvas,并渲染当前图像                surfaceHolder.unlockCanvasAndPost(canvas);  // ②                try                {                    Thread.sleep(60);                }                catch (InterruptedException e){}            }        }        public void requestExitAndWait()        {            // 把这个线程标记为完成,并合并到主程序线程            done = true;            try            {                join();            }            catch (InterruptedException ex){}        }        public void onWindowResize(int w, int h){            // 处理SurfaceView的大小改变事件        }    }}

动画四

MainActivity代码:

public class MainActivity extends Activity{    private SurfaceHolder holder;    private Paint paint;    final int HEIGHT = 320;    final int WIDTH = 768;    final int X_OFFSET = 5;    private int cx = X_OFFSET;    // 实际的Y轴的位置    int centerY = HEIGHT / 2;    Timer timer = new Timer();    TimerTask task = null;    @Override    public void onCreate(Bundle savedInstanceState)    {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        final SurfaceView surface = (SurfaceView)                findViewById(R.id.show);        // 初始化SurfaceHolder对象        holder = surface.getHolder();        paint = new Paint();        paint.setColor(Color.GREEN);        paint.setStrokeWidth(3);        Button sin = (Button)findViewById(R.id.sin);        Button cos = (Button)findViewById(R.id.cos);        OnClickListener listener = (new OnClickListener()        {            @Override            public void onClick(final View source)            {                drawBack(holder);                cx = X_OFFSET;                if(task != null)                {                    task.cancel();                }                task = new TimerTask()                {                    public void run()                    {                        int cy = source.getId() == R.id.sin ? centerY                                - (int)(100 * Math.sin((cx - 5) * 2                                * Math.PI / 150))                                : centerY - (int)(100 * Math.cos ((cx - 5)                                * 2 * Math.PI / 150));                        Canvas canvas = holder.lockCanvas(new Rect(cx ,                                cy - 2  , cx + 2, cy + 2));                        canvas.drawPoint(cx , cy , paint);                        cx ++;                        if (cx > WIDTH)                        {                            task.cancel();                            task = null;                        }                        holder.unlockCanvasAndPost(canvas);                    }                };                timer.schedule(task , 0 , 30);            }        });        sin.setOnClickListener(listener);        cos.setOnClickListener(listener);        holder.addCallback(new Callback()        {            @Override            public void surfaceChanged(SurfaceHolder holder, int format,                                       int width, int height)            {                drawBack(holder);            }            @Override            public void surfaceCreated(final SurfaceHolder myHolder){ }            @Override            public void surfaceDestroyed(SurfaceHolder holder)            {                timer.cancel();            }        });    }    private void drawBack(SurfaceHolder holder)    {        Canvas canvas = holder.lockCanvas();        // 绘制白色背景        canvas.drawColor(Color.WHITE);        Paint p = new Paint();        p.setColor(Color.BLACK);        p.setStrokeWidth(2);        // 绘制坐标轴        canvas.drawLine(X_OFFSET , centerY , WIDTH , centerY , p);        canvas.drawLine(X_OFFSET , 40 , X_OFFSET , HEIGHT , p);        holder.unlockCanvasAndPost(canvas);        holder.lockCanvas(new Rect(0 , 0 , 0 , 0));        holder.unlockCanvasAndPost(canvas);    }}

更多相关文章

  1. Android(安卓)自定义控件属性,自定义Dialog定位
  2. android中自定义的控件,使用自定义属性attrs.xml
  3. Android(安卓)Widget ListView添加点击事件
  4. Android中的android:layout_weight使用详解
  5. android 如何连真机测试
  6. android eclipse环境搭建
  7. Mac OS X下设置android NDK的环境(详细实测有图)
  8. Android7.1启动系统App必须配置加密
  9. Android(安卓)Api demo系列(一) (App>Activity>Animation)

随机推荐

  1. LinearLayout布局之weight
  2. Android中文API(129) —— AudioManager
  3. Android AM命令行启动程序的方法
  4. [连载 1/15] Android 从入门到精通Exampl
  5. Android DownloadManager下载完成事件监
  6. android:visibility="gone"
  7. Android 利用shape自定义进度条样式
  8. android adb pm命令
  9. Android Gradle基础实践
  10. android 二级菜单、双ListView 仿美团、