Android进阶篇之引导页系列之强大的SurfaceView实现动画引导页(2)
2016-02-23 15:13
225 查看
咱们继续上次所说的SurfaceView实现动画引导页,(其实文中是有代码下载地址的,不明显而已,源码下载)
今天的任务量很少,主要就是实现一个效果,就是实现在同一个地球表面上进行翻页效果,如下图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/201911/13/9a914acd2d7c6be82528c5c5b6625f1d)
效果就是下面的地球随着翻页进行可以转动,然后出现不同页面,不同页面再进行动画渲染。
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/wail.gif)
<PS:不会简单制作gif,所以动画效果请筒子们各自进行脑补>
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/knock.gif)
,如果谁能行行好,教我怎么简单快速制作gif就感谢不过了<不会有报酬的哟
![](https://oscdn.geek-share.com/Uploads/Images/Content/201707/6bb3f2a2eb81f326445a31770403c7f1.gif)
>。
SurfaceView的框架还是上次的,我们先来分析一下今天需要的资源:
1,背景,因为这里的背景没有什么边框,所以直接使用色值,取色就可以解决了<其实个人觉得,引导动画的背景就不宜使用图片,至于为什么之前分析过了
![](https://oscdn.geek-share.com/Uploads/Images/Content/201603/899229cfab2c02d614490485cabb781b.gif)
>,
// 白天的背景
206,238,253
// 黑夜的背景 29, 54, 82
2,然后是一整张地图的资源,这个必须是图片了哈哈。。。
[java] view
plain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
private Bitmap bmpEart = null; //地图资源
private int bmpEartX, bmpEartY ; //地球资源的坐标
private int ratX, ratY ; //旋转中心点的坐标
plain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/** 当前页的序号,第一页是0 */
int currentViewNo = 0;
//计时器的分量,比如设为30,就是同一个逻辑执行30次,设置为-1,主要是因为控制是否是第一次进入应用
//第一次进入应用,没有需要控制计时器的分量,计时器的分量只是控制地图转动的时间
//第一次进入应用地球不需要转动,所以oneTopCtrl的值不能大于-1,在logic函数中是这么定义的
private int oneTopCtrl = -1;
float oneEartRatOut = 0; //旋转的角度
int sign = -1; //手势滑动方向标
plain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/**
* 初始化所用资源
*/
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?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/**
* 触屏监听事件
*/
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;
}
plain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/**
* 页面逻辑
*/
public void logic() {
//oneTopCtrl控制旋转的时间和角度,设置为30,每次增减3*sign<-1或者1>,所以每次旋转的角度就是90度
if (oneTopCtrl >= 0 && oneTopCtrl < 30) {
oneTopCtrl++;
oneEartRatOut += 3 * sign;
if (oneEartRatOut > 360) {
oneEartRatOut %= 360;
}
}
}
plain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
/**
* 绘制画面
*/
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?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
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?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/9e12f1d3e499fc949c886e7c9e0484f9)
</pre><pre code_snippet_id="652296" snippet_file_name="blog_20150424_9_8056625" name="code" class="java">
今天的任务量很少,主要就是实现一个效果,就是实现在同一个地球表面上进行翻页效果,如下图:
效果就是下面的地球随着翻页进行可以转动,然后出现不同页面,不同页面再进行动画渲染。
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/wail.gif)
<PS:不会简单制作gif,所以动画效果请筒子们各自进行脑补>
![](http://static.blog.csdn.net/xheditor/xheditor_emot/default/knock.gif)
,如果谁能行行好,教我怎么简单快速制作gif就感谢不过了<不会有报酬的哟
![](https://oscdn.geek-share.com/Uploads/Images/Content/201707/6bb3f2a2eb81f326445a31770403c7f1.gif)
>。
SurfaceView的框架还是上次的,我们先来分析一下今天需要的资源:
1,背景,因为这里的背景没有什么边框,所以直接使用色值,取色就可以解决了<其实个人觉得,引导动画的背景就不宜使用图片,至于为什么之前分析过了
![](https://oscdn.geek-share.com/Uploads/Images/Content/201603/899229cfab2c02d614490485cabb781b.gif)
>,
// 白天的背景
206,238,253
// 黑夜的背景 29, 54, 82
2,然后是一整张地图的资源,这个必须是图片了哈哈。。。
资源声明
[java] viewplain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
private Bitmap bmpEart = null; //地图资源
private int bmpEartX, bmpEartY ; //地球资源的坐标
private int ratX, ratY ; //旋转中心点的坐标
逻辑控制量声明
[java] viewplain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/** 当前页的序号,第一页是0 */
int currentViewNo = 0;
//计时器的分量,比如设为30,就是同一个逻辑执行30次,设置为-1,主要是因为控制是否是第一次进入应用
//第一次进入应用,没有需要控制计时器的分量,计时器的分量只是控制地图转动的时间
//第一次进入应用地球不需要转动,所以oneTopCtrl的值不能大于-1,在logic函数中是这么定义的
private int oneTopCtrl = -1;
float oneEartRatOut = 0; //旋转的角度
int sign = -1; //手势滑动方向标
初始化资源
[java] viewplain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/**
* 初始化所用资源
*/
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] viewplain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/**
* 触屏监听事件
*/
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] viewplain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/**
* 页面逻辑
*/
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] viewplain copy
print?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
/**
* 绘制画面
*/
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?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
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?
![](https://oscdn.geek-share.com/Uploads/Images/Content/201611/a7c8e286f463007e2a900848b93dd72c.png)
</pre><pre code_snippet_id="652296" snippet_file_name="blog_20150424_9_8056625" name="code" class="java">
相关文章推荐
- android的task任务栈
- Android 如何让EditText不自动获取焦点
- Android进阶篇之引导页系列之强大的SurfaceView实现动画引导页(1)
- 浅学使用Android的mvp模式+otto消息总线
- Android 多线程
- Android进阶篇之引导页系列之ViewPager实现Animation动画引导页
- Android应用如何实现换肤功能
- Android TextView丰富多彩的字体样式代码
- Android开发之旅: Intents和Intent Filters(理论部分)
- Android中对闹钟Alarm的事件处理
- android如何调用显示和隐藏系统默认的输入法
- Android中EditText.setText(String)方法导致输入法跳转
- Android 实现个性的ViewPager切换动画 实战PageTransformer(兼容Android3.0以下)
- 2015年Android作品集
- View位置参数
- Android IntentService完全解析 当Service遇到Handler
- 安卓开发基础之动画(一)补间动画的各种效果的实现
- mac中Android环境的搭建
- Android设置虚线、圆角、渐变
- android反编译工具之jadx简介