您的位置:首页 > 移动开发 > Android开发

Android进阶篇之引导页系列之强大的SurfaceView实现动画引导页(2)

2016-02-23 15:13 225 查看
咱们继续上次所说的SurfaceView实现动画引导页,(其实文中是有代码下载地址的,不明显而已,源码下载

今天的任务量很少,主要就是实现一个效果,就是实现在同一个地球表面上进行翻页效果,如下图:



效果就是下面的地球随着翻页进行可以转动,然后出现不同页面,不同页面再进行动画渲染。

<PS:不会简单制作gif,所以动画效果请筒子们各自进行脑补>

,如果谁能行行好,教我怎么简单快速制作gif就感谢不过了<不会有报酬的哟

>。

SurfaceView的框架还是上次的,我们先来分析一下今天需要的资源:

1,背景,因为这里的背景没有什么边框,所以直接使用色值,取色就可以解决了<其实个人觉得,引导动画的背景就不宜使用图片,至于为什么之前分析过了

>,

// 白天的背景
206,238,253

// 黑夜的背景 29, 54, 82

2,然后是一整张地图的资源,这个必须是图片了哈哈。。。


资源声明

[java] view
plain copy

print?





private Bitmap bmpEart = null; //地图资源

private int bmpEartX, bmpEartY ; //地球资源的坐标

private int ratX, ratY ; //旋转中心点的坐标

逻辑控制量声明

[java] view
plain copy

print?





/** 当前页的序号,第一页是0 */

int currentViewNo = 0;

//计时器的分量,比如设为30,就是同一个逻辑执行30次,设置为-1,主要是因为控制是否是第一次进入应用

//第一次进入应用,没有需要控制计时器的分量,计时器的分量只是控制地图转动的时间

//第一次进入应用地球不需要转动,所以oneTopCtrl的值不能大于-1,在logic函数中是这么定义的

private int oneTopCtrl = -1;

float oneEartRatOut = 0; //旋转的角度

int sign = -1; //手势滑动方向标

初始化资源

[java] view
plain copy

print?





/**

* 初始化所用资源

*/

private void initData() {

//初始化地球资源

bmpEart = (Bitmap) BitmapFactory.decodeResource(getResources(),

R.drawable.revolve_ground);

//初始化所有资源坐标

initAllXY();

}

/**

* 初始化所有坐标点

*/

private void initAllXY() {

bmpEartX = screenW / 2 - bmpEart.getWidth() / 2;

bmpEartY = screenH - bmpEart.getHeight() / 4;

ratX = screenW / 2;

ratY = screenH + bmpEart.getHeight() / 4;

}

重点来了:因为初始化资源所用到的变量有屏幕的宽和高,所以initData函数就必须放在surfaceCreated中。其实也不难理解,如果放在构造函数中,主View还没有被测量出来,所以宽和高都是0,如果把initData放在构造函数,所有的坐标初始化那就是错的了。

因为这个设计到手势,目前只是简单判断一下滑动的方向,所以不需要太复杂


手势滑动方向判断

[java] view
plain copy

print?





/**

* 触屏监听事件

*/

private VelocityTracker mVt = null;

int detaX = 0; // 手指移动的x轴相对位移

int tmpX = 0, tmpY = 0; // Move时刻坐标点

int startX = 0, startY = 0;

int endX = 0, endY = 0;

@Override

public boolean onTouchEvent(MotionEvent event) {

synchronized (event) {

int action = event.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

// 手指按下

startX = (int) event.getX();

startY = (int) event.getY();

break;

case MotionEvent.ACTION_MOVE:

// 添加采样点

// mVt.addMovement(event);

tmpX = (int) event.getX();

tmpY = (int) event.getY();

break;

case MotionEvent.ACTION_UP:

// 手指移动

endX = (int) event.getX();

endY = (int) event.getY();

int tmp = (endX - startX);

int dir = judgeDir(startX, startY, endX, endY);

if (dir == 1) {// right

if (currentViewNo > 0) {

sign = 1;

oneTopCtrl = 0;

currentViewNo--;

}

} else if (dir == 2) {// left

if (currentViewNo < 3) {

sign = -1;

oneTopCtrl = 0;

currentViewNo++;

}

}

break;

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_OUTSIDE:

// 触摸事件结束

// 设置速度的时间单位 1代表每毫秒移动多少像素 1000代表每秒移动多少像素

// 这个方法在获得速度之前必须要设置

mVt.clear();// 清空

mVt.recycle();// 回收vt对象的内存

break;

}

}

return true;

}

/**

* 手势方向判别

*

*/

private int judgeDir(int startX, int startY, int endX, int endY) {

if ((endX - startX) > 0 && Math.abs(endX - startX) > screenW / 3) {

// 方向是正右方 1

return 1;

} else if ((endX - startX) < 0 && Math.abs(endX - startX) > screenW / 3) {

// 方向是正左方 2

return 2;

}

return 0;

}

逻辑函数处理

[java] view
plain copy

print?





/**

* 页面逻辑

*/

public void logic() {

//oneTopCtrl控制旋转的时间和角度,设置为30,每次增减3*sign<-1或者1>,所以每次旋转的角度就是90度

if (oneTopCtrl >= 0 && oneTopCtrl < 30) {

oneTopCtrl++;

oneEartRatOut += 3 * sign;

if (oneEartRatOut > 360) {

oneEartRatOut %= 360;

}

}

}

绘制View

[java] view
plain copy

print?





/**

* 绘制画面

*/

public void myDraw() {

try {

canvas = sfh.lockCanvas();

if (canvas != null) {

canvas.drawColor(context.getResources().getColor(R.color.bg));//刷新屏幕,用背景色刷新

canvas.save(); //注意canvas.save()与canvas,restore()是成对存在的

canvas.rotate(oneEartRatOut, ratX, ratY); //旋转控制的角度

canvas.drawBitmap(bmpEart, bmpEartX, bmpEartY, paint);//绘制地图

canvas.restore();

}

} catch (Exception e) {

} finally {

if (canvas != null) {

sfh.unlockCanvasAndPost(canvas);

}

}

}

实现这个效果还是很简单的,利用前面说的游戏框架,我们现在要做的就只有三件事:声明与初始化资源和控制量,处理触屏逻辑和页面绘制逻辑,最后在myDraw函数中绘制画面。
个人觉得最难的部分是第二步,就是逻辑控制了,游戏亦是如此,更好玩的游戏逻辑用户就玩的更爽,也就更复杂。所以一般写多了自定义,就会发现绘制View不是复杂的,复杂的是逻辑。
触屏逻辑和时间线一般是作为出发点,一般都是这两种逻辑控制页面逻辑<logic函数>。

给一个源码下载

下面给出完整的代码

[java] view
plain copy

print?





import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.transition.Scene;

import android.view.MotionEvent;

import android.view.SurfaceHolder;

import android.view.SurfaceHolder.Callback;

import android.view.SurfaceView;

import android.view.VelocityTracker;

import android.widget.Toast;

public class MySurfaceView extends SurfaceView implements Callback, Runnable {

private Context context = null;

// 用于控制SurfaceView

private SurfaceHolder sfh = null;

// 声明一个画笔

private Paint paint;

// 声明一条线程

private Thread th = null;

// 用于控制线程的标识符

private boolean flag;

// 声明一个画布

private Canvas canvas;

// 定义高和宽

public static int screenW, screenH;

/** 当前页的序号,第一页是0 */

int currentViewNo = 0;

//计时器的分量,比如设为30,就是同一个逻辑执行30次,设置为-1,主要是因为控制是否是第一次进入应用

//第一次进入应用,没有需要控制计时器的分量,计时器的分量只是控制地图转动的时间

//第一次进入应用地球不需要转动,所以oneTopCtrl的值不能大于-1,在logic函数中是这么定义的

private int oneTopCtrl = -1;

float oneEartRatOut = 0; //旋转的角度

int sign = -1; //手势滑动方向标

private Bitmap bmpEart = null; //地图资源

private int bmpEartX, bmpEartY ; //地球资源的坐标

private int ratX, ratY ; //旋转中心点的坐标

public MySurfaceView(Context context) {

super(context);

this.context = context;

// ///////////SurfaceView框架/////////////////////////////

sfh = (SurfaceHolder) this.getHolder();

sfh.addCallback(this);

canvas = new Canvas();

paint = new Paint();

paint.setColor(Color.WHITE);

paint.setAntiAlias(true);

this.setFocusable(true);

}

@Override

public void surfaceCreated(SurfaceHolder holder) {

screenW = this.getWidth();

screenH = this.getHeight();

// ///////////资源初始化////////////////////////////////

initData();

flag = true;

th = new Thread(this);

th.start();

}

/**

* 绘制画面

*/

public void myDraw() {

try {

canvas = sfh.lockCanvas();

if (canvas != null) {

canvas.drawColor(context.getResources().getColor(R.color.bg));//刷新屏幕,用背景色刷新

canvas.save(); //注意canvas.save()与canvas,restore()是成对存在的

canvas.rotate(oneEartRatOut, ratX, ratY); //旋转控制的角度

canvas.drawBitmap(bmpEart, bmpEartX, bmpEartY, paint);//绘制地图

canvas.restore();

}

} catch (Exception e) {

} finally {

if (canvas != null) {

sfh.unlockCanvasAndPost(canvas);

}

}

}

/**

* 页面逻辑

*/

public void logic() {

//oneTopCtrl控制旋转的时间和角度,设置为30,每次增减3*sign<-1或者1>,所以每次旋转的角度就是90度

if (oneTopCtrl >= 0 && oneTopCtrl < 30) {

oneTopCtrl++;

oneEartRatOut += 3 * sign;

if (oneEartRatOut > 360) {

oneEartRatOut %= 360;

}

}

}

/**

* 触屏监听事件

*/

private VelocityTracker mVt = null;

int detaX = 0; // 手指移动的x轴相对位移

int tmpX = 0, tmpY = 0; // Move时刻坐标点

int startX = 0, startY = 0;

int endX = 0, endY = 0;

@Override

public boolean onTouchEvent(MotionEvent event) {

synchronized (event) {

int action = event.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

// 手指按下

startX = (int) event.getX();

startY = (int) event.getY();

break;

case MotionEvent.ACTION_MOVE:

// 添加采样点

// mVt.addMovement(event);

tmpX = (int) event.getX();

tmpY = (int) event.getY();

break;

case MotionEvent.ACTION_UP:

// 手指移动

endX = (int) event.getX();

endY = (int) event.getY();

int tmp = (endX - startX);

int dir = judgeDir(startX, startY, endX, endY);

if (dir == 1) {// right

if (currentViewNo > 0) {

sign = 1;

oneTopCtrl = 0;

currentViewNo--;

}

} else if (dir == 2) {// left

if (currentViewNo < 3) {

sign = -1;

oneTopCtrl = 0;

currentViewNo++;

}

}

break;

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_OUTSIDE:

// 触摸事件结束

// 设置速度的时间单位 1代表每毫秒移动多少像素 1000代表每秒移动多少像素

// 这个方法在获得速度之前必须要设置

mVt.clear();// 清空

mVt.recycle();// 回收vt对象的内存

break;

}

}

return true;

}

/**

* 手势方向判别

*

*/

private int judgeDir(int startX, int startY, int endX, int endY) {

if ((endX - startX) > 0 && Math.abs(endX - startX) > screenW / 3) {

// 方向是正右方 1

return 1;

} else if ((endX - startX) < 0 && Math.abs(endX - startX) > screenW / 3) {

// 方向是正左方 2

return 2;

}

return 0;

}

@Override

public void run() {

while (flag) {

long start = System.currentTimeMillis();

myDraw();

logic();

long end = System.currentTimeMillis();

try {

if (end - start < 50) {

Thread.sleep(50 - (end - start));

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

/**

* 画布状态改变监听事件

*/

@Override

public void surfaceChanged(SurfaceHolder holder, int format, int width,

int height) {

}

/**

* 画布被摧毁事件

*/

@Override

public void surfaceDestroyed(SurfaceHolder holder) {

flag = false;

}

/**

* 初始化所用资源

*/

private void initData() {

//初始化地球资源

bmpEart = (Bitmap) BitmapFactory.decodeResource(getResources(),

R.drawable.revolve_ground);

//初始化所有资源坐标

initAllXY();

}

/**

* 初始化所有坐标点

*/

private void initAllXY() {

bmpEartX = screenW / 2 - bmpEart.getWidth() / 2;

bmpEartY = screenH - bmpEart.getHeight() / 4;

ratX = screenW / 2;

ratY = screenH + bmpEart.getHeight() / 4;

}

}

[java] view
plain copy

print?





</pre><pre code_snippet_id="652296" snippet_file_name="blog_20150424_9_8056625" name="code" class="java">
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: