65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 SurfaceView 进行动画

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.40/5 (5投票s)

2013年9月5日

CPOL

2分钟阅读

viewsIcon

36052

downloadIcon

1264

本文介绍一种使用 Canvas、Paint 和 SurfaceView 开发动画的解决方案。

引言

实际上,您可能遇到一些类似的需求:**使列表自动滚动,中心图像会放大...** 遇到这类需求,Android 中似乎没有现成的 View 可以直接满足,您必须自定义。

通常,我认为几乎所有开发者都必须解决的最重要的一点是 View 动画。

今天,我将指导您完成一个在 Android 开发中自定义 View 的解决方案,即 SurfaceView 中的 **动画**。 我也写过一些关于它的文章,例如 半圆形列表视图自动滑动列表视图,等等。

本文只是我的一些想法,可能不是最佳解决方案。但我希望我能为您提供一种继续进行 Android 自定义 View 开发的途径。

背景

许多开发者认为,SurfaceView 在 Android 中非常特殊。不,它只是一个普通的 View。不同之处在于它可以在后台线程中绘制(View 的 onDraw() 必须在 UI 线程中执行)。总结来说,执行动画的方式将执行以下两个函数:

  • 更新视图的属性坐标、alpha、缩放。
  • 使用更新后的属性绘制视图。

为此,请使用 CanvasPaint我将通过一个 Bitmap 的示例来帮助您理解下面的代码:

canvas.drawBitmap(mBitmap, x, y, paint);

平移 mBitmap,更新 **x, y**

淡出淡入 mBitmap,更新 alpha 值(在 paint 中)

paint.setAlpha((int) alpha);  

缩放 mBitmap,更新 canvas 的 scale 属性。

canvas.scale(scaleValue, 1, mBitmap.getWidth() / 2, mBitmap.getHeight() / 2);  

旋转 mBitmap,您可以更新 matrix 值。请参考此处获取更多详细信息。

动画呢?

基于上述想法,如果我们能给出一个公式来更新 mBitmap 的属性,我们就可以执行动画。请考虑一个简单的示例:

假设从时间 **t1** 到时间 **t2**,视图从 **x1** 平移到 **x2**。在时间 **t** 时视图的坐标是多少?公式将是:x = x1 + t * (x2-x1) / (t2-t1)

使用代码

Animation.java

基于以上想法,我创建了一个简单的 Animation 类,用于计算当前值,具有以下属性:

  • mStartValue:动画开始时的初始值。
  • mEndValue:动画结束时的最终值。
  • mDuration:从 mStartValue 更改到 mEndValue 的持续时间。
  • mStartTime:动画开始的时间。动画开始时,通过 System.currentTimeMillis() 获取。
  • mEndTime:动画结束的时间。 mEndTime = mStartTime + mDuration
在指定时间获取当前值的方法是:
public float getCurrentValue(long currentTime) {
   float currentValue = mStartValue + (currentTime)
                * (mEndValue - mStartValue) / mDuration;
   if (currentTime > mEndTime) {
           currentValue = mEndValue;
   }
   return currentValue; 
}   

扩展 Animation.java,我们有 AlphaAnimation、ScaleXAnimation、ScaleYAnimation、TranslateXAnimation、TranslateYAnimation

要在 3 秒内将位图从 [x = 0] 平移到 [x = 屏幕宽度],您可以创建 TranslateXAnimation

animation = new TranslateXAnimation();
animation.mDuration = 3000;
animation.mStartTime = System.currentTimeMillis();
animation.mEndTime = System.currentTimeMillis() + 3000;
animation.mStartValue = 0;
animation.mEndValue = SCREEN_WIDTH;   

要在 3 秒内将位图从 [y = 0] 平移到 [y = 屏幕高度],您可以创建 TranslateYAnimation

animation = new TranslateYAnimation();
animation.mDuration = 3000;
animation.mStartTime = System.currentTimeMillis();
animation.mEndTime = System.currentTimeMillis() + 3000;
animation.mStartValue = 0;
animation.mEndValue = SCREEN_HEIGHT;  

要将位图从 alpha = 0 淡入到 alpha = 255,请创建 AlphaAnimation

animation = new AlphaAnimation();
animation.mDuration = 3000;
animation.mStartTime = System.currentTimeMillis();
animation.mEndTime = System.currentTimeMillis() + 3000;
animation.mStartValue = 0;
animation.mEndValue = 255;  

要在 SurfaceView 中绘制位图,请根据动画类型在后台应用相应的方法。

if (animation.mType == Type.TranslateX) {
                float currentX = animation.getCurrentValue(System
                        .currentTimeMillis() - animation.mStartTime);
                canvas.drawBitmap(mBitmap, currentX, Y_DEFAULT_COORDINATE,
                        paint);
            } else if (animation.mType == Type.TranslateY) {
                float currentY = animation.getCurrentValue(System
                        .currentTimeMillis() - animation.mStartTime);
                canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE, currentY,
                        paint);
            } else if (animation.mType == Type.ScaleX) {
                float currentY = animation.getCurrentValue(System
                        .currentTimeMillis() - animation.mStartTime);
                // canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE, currentY,
                // paint);
                canvas.scale(currentY, 1, mBitmap.getWidth() / 2,
                        mBitmap.getHeight() / 2);
                canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE,
                        Y_DEFAULT_COORDINATE, paint);
            } else if (animation.mType == Type.ScaleY) {
                float currentY = animation.getCurrentValue(System
                        .currentTimeMillis() - animation.mStartTime);
                // canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE, currentY,
                // paint);
                canvas.scale(1, currentY, mBitmap.getWidth() / 2,
                        mBitmap.getHeight() / 2);
                canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE,
                        Y_DEFAULT_COORDINATE, paint);
            } else if (animation.mType == Type.Alpha) {
                float alpha = animation.getCurrentValue(System
                        .currentTimeMillis() - animation.mStartTime);
                // canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE, currentY,
                // paint);
                paint.setAlpha((int) alpha);
                canvas.drawBitmap(mBitmap, X_DEFAULT_COORDINATE,
                        Y_DEFAULT_COORDINATE, paint);
            }  

历史 

20130905:首次创建。

© . All rights reserved.