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

来源:互联网 发布:muscletech淘宝真假 编辑:程序博客网 时间:2024/05/29 02:32

咱们继续上次所说的SurfaceView实现动画引导页

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


效果就是下面的地球随着翻页进行可以转动,然后出现不同页面,不同页面再进行动画渲染。大哭<PS:不会简单制作gif,所以动画效果请筒子们各自进行脑补>敲打,如果谁能行行好,教我怎么简单快速制作gif就感谢不过了<不会有报酬的哟害羞>。

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

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

// 白天的背景  206,238,253
// 黑夜的背景       29, 54, 82

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

资源声明

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. private Bitmap bmpEart = null;  //地图资源  
  2. private int bmpEartX, bmpEartY ;    //地球资源的坐标  
  3. private int ratX, ratY ;    //旋转中心点的坐标  

逻辑控制量声明

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 当前页的序号,第一页是0 */  
  2. int currentViewNo = 0;  
  3. //计时器的分量,比如设为30,就是同一个逻辑执行30次,设置为-1,主要是因为控制是否是第一次进入应用  
  4. //第一次进入应用,没有需要控制计时器的分量,计时器的分量只是控制地图转动的时间  
  5. //第一次进入应用地球不需要转动,所以oneTopCtrl的值不能大于-1,在logic函数中是这么定义的  
  6. private int oneTopCtrl = -1;  
  7. float oneEartRatOut = 0;    //旋转的角度  
  8. int sign = -1;  //手势滑动方向标  

初始化资源

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 初始化所用资源 
  3.  */  
  4. private void initData() {  
  5.     //初始化地球资源  
  6.     bmpEart = (Bitmap) BitmapFactory.decodeResource(getResources(),  
  7.             R.drawable.revolve_ground);  
  8.     //初始化所有资源坐标  
  9.     initAllXY();  
  10. }  
  11. /** 
  12.  * 初始化所有坐标点 
  13.  */  
  14. private void initAllXY() {  
  15.     bmpEartX = screenW / 2 - bmpEart.getWidth() / 2;  
  16.     bmpEartY = screenH - bmpEart.getHeight() / 4;  
  17.       
  18.     ratX = screenW / 2;  
  19.     ratY = screenH + bmpEart.getHeight() / 4;  
  20. }  

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

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

手势滑动方向判断

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 触屏监听事件 
  3.  */  
  4. private VelocityTracker mVt = null;  
  5.   
  6. int detaX = 0// 手指移动的x轴相对位移  
  7. int tmpX = 0, tmpY = 0// Move时刻坐标点  
  8.   
  9. int startX = 0, startY = 0;  
  10. int endX = 0, endY = 0;  
  11.   
  12. @Override  
  13. public boolean onTouchEvent(MotionEvent event) {  
  14.     synchronized (event) {  
  15.         int action = event.getAction();  
  16.         switch (action) {  
  17.         case MotionEvent.ACTION_DOWN:  
  18.             // 手指按下  
  19.             startX = (int) event.getX();  
  20.             startY = (int) event.getY();  
  21.             break;  
  22.         case MotionEvent.ACTION_MOVE:  
  23.             // 添加采样点  
  24.             // mVt.addMovement(event);  
  25.             tmpX = (int) event.getX();  
  26.             tmpY = (int) event.getY();  
  27.             break;  
  28.         case MotionEvent.ACTION_UP:  
  29.             // 手指移动  
  30.             endX = (int) event.getX();  
  31.             endY = (int) event.getY();  
  32.             int tmp = (endX - startX);  
  33.   
  34.             int dir = judgeDir(startX, startY, endX, endY);  
  35.   
  36.             if (dir == 1) {// right  
  37.                 if (currentViewNo > 0) {  
  38.                     sign = 1;  
  39.                     oneTopCtrl = 0;  
  40.                     currentViewNo--;  
  41.                 }  
  42.             } else if (dir == 2) {// left  
  43.                 if (currentViewNo < 3) {  
  44.                     sign = -1;  
  45.                     oneTopCtrl = 0;  
  46.                     currentViewNo++;  
  47.                 }  
  48.             }  
  49.             break;  
  50.         case MotionEvent.ACTION_CANCEL:  
  51.         case MotionEvent.ACTION_OUTSIDE:  
  52.             // 触摸事件结束  
  53.             // 设置速度的时间单位 1代表每毫秒移动多少像素 1000代表每秒移动多少像素  
  54.             // 这个方法在获得速度之前必须要设置  
  55.             mVt.clear();// 清空  
  56.             mVt.recycle();// 回收vt对象的内存  
  57.             break;  
  58.         }  
  59.     }  
  60.     return true;  
  61. }  
  62.   
  63. /** 
  64.  * 手势方向判别 
  65.  *  
  66.  */  
  67. private int judgeDir(int startX, int startY, int endX, int endY) {  
  68.   
  69.     if ((endX - startX) > 0 && Math.abs(endX - startX) > screenW / 3) {  
  70.         // 方向是正右方 1  
  71.         return 1;  
  72.     } else if ((endX - startX) < 0 && Math.abs(endX - startX) > screenW / 3) {  
  73.         // 方向是正左方 2  
  74.         return 2;  
  75.     }  
  76.     return 0;  
  77. }  

逻辑函数处理

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 页面逻辑 
  3.  */  
  4. public void logic() {  
  5.     //oneTopCtrl控制旋转的时间和角度,设置为30,每次增减3*sign<-1或者1>,所以每次旋转的角度就是90度  
  6.     if (oneTopCtrl >= 0 && oneTopCtrl < 30) {  
  7.         oneTopCtrl++;  
  8.         oneEartRatOut += 3 * sign;  
  9.         if (oneEartRatOut > 360) {  
  10.             oneEartRatOut %= 360;  
  11.         }  
  12.     }  
  13. }  

绘制View

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. /** 
  2.  * 绘制画面 
  3.  */  
  4. public void myDraw() {  
  5.     try {  
  6.         canvas = sfh.lockCanvas();  
  7.         if (canvas != null) {  
  8.             canvas.drawColor(context.getResources().getColor(R.color.bg));//刷新屏幕,用背景色刷新  
  9.             canvas.save();  //注意canvas.save()与canvas,restore()是成对存在的  
  10.             canvas.rotate(oneEartRatOut, ratX, ratY);   //旋转控制的角度  
  11.             canvas.drawBitmap(bmpEart, bmpEartX, bmpEartY, paint);//绘制地图  
  12.             canvas.restore();  
  13.         }  
  14.     } catch (Exception e) {  
  15.   
  16.     } finally {  
  17.         if (canvas != null) {  
  18.             sfh.unlockCanvasAndPost(canvas);  
  19.         }  
  20.     }  
  21. }  

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

给一个源码下载

下面给出完整的代码

[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1. import android.content.Context;  
  2. import android.graphics.Bitmap;  
  3. import android.graphics.BitmapFactory;  
  4. import android.graphics.Canvas;  
  5. import android.graphics.Color;  
  6. import android.graphics.Paint;  
  7. import android.transition.Scene;  
  8. import android.view.MotionEvent;  
  9. import android.view.SurfaceHolder;  
  10. import android.view.SurfaceHolder.Callback;  
  11. import android.view.SurfaceView;  
  12. import android.view.VelocityTracker;  
  13. import android.widget.Toast;  
  14.   
  15. public class MySurfaceView extends SurfaceView implements Callback, Runnable {  
  16.   
  17.     private Context context = null;  
  18.   
  19.     // 用于控制SurfaceView  
  20.     private SurfaceHolder sfh = null;  
  21.     // 声明一个画笔  
  22.     private Paint paint;  
  23.     // 声明一条线程  
  24.     private Thread th = null;  
  25.     // 用于控制线程的标识符  
  26.     private boolean flag;  
  27.     // 声明一个画布  
  28.     private Canvas canvas;  
  29.     // 定义高和宽  
  30.     public static int screenW, screenH;  
  31.   
  32.     /** 当前页的序号,第一页是0 */  
  33.     int currentViewNo = 0;  
  34.     //计时器的分量,比如设为30,就是同一个逻辑执行30次,设置为-1,主要是因为控制是否是第一次进入应用  
  35.     //第一次进入应用,没有需要控制计时器的分量,计时器的分量只是控制地图转动的时间  
  36.     //第一次进入应用地球不需要转动,所以oneTopCtrl的值不能大于-1,在logic函数中是这么定义的  
  37.     private int oneTopCtrl = -1;  
  38.     float oneEartRatOut = 0;    //旋转的角度  
  39.     int sign = -1;  //手势滑动方向标  
  40.       
  41.     private Bitmap bmpEart = null;  //地图资源  
  42.     private int bmpEartX, bmpEartY ;    //地球资源的坐标  
  43.     private int ratX, ratY ;    //旋转中心点的坐标  
  44.       
  45.     public MySurfaceView(Context context) {  
  46.         super(context);  
  47.         this.context = context;  
  48.         // ///////////SurfaceView框架/////////////////////////////  
  49.         sfh = (SurfaceHolder) this.getHolder();  
  50.         sfh.addCallback(this);  
  51.         canvas = new Canvas();  
  52.         paint = new Paint();  
  53.         paint.setColor(Color.WHITE);  
  54.         paint.setAntiAlias(true);  
  55.         this.setFocusable(true);      
  56.     }  
  57.   
  58.     @Override  
  59.     public void surfaceCreated(SurfaceHolder holder) {  
  60.   
  61.         screenW = this.getWidth();  
  62.         screenH = this.getHeight();  
  63.         // ///////////资源初始化////////////////////////////////  
  64.         initData();  
  65.                   
  66.         flag = true;  
  67.         th = new Thread(this);  
  68.         th.start();  
  69.     }  
  70.   
  71.     /** 
  72.      * 绘制画面 
  73.      */  
  74.     public void myDraw() {  
  75.         try {  
  76.             canvas = sfh.lockCanvas();  
  77.             if (canvas != null) {  
  78.                 canvas.drawColor(context.getResources().getColor(R.color.bg));//刷新屏幕,用背景色刷新  
  79.                 canvas.save();  //注意canvas.save()与canvas,restore()是成对存在的  
  80.                 canvas.rotate(oneEartRatOut, ratX, ratY);   //旋转控制的角度  
  81.                 canvas.drawBitmap(bmpEart, bmpEartX, bmpEartY, paint);//绘制地图  
  82.                 canvas.restore();  
  83.             }  
  84.         } catch (Exception e) {  
  85.   
  86.         } finally {  
  87.             if (canvas != null) {  
  88.                 sfh.unlockCanvasAndPost(canvas);  
  89.             }  
  90.         }  
  91.     }  
  92.   
  93.     /** 
  94.      * 页面逻辑 
  95.      */  
  96.     public void logic() {  
  97.         //oneTopCtrl控制旋转的时间和角度,设置为30,每次增减3*sign<-1或者1>,所以每次旋转的角度就是90度  
  98.         if (oneTopCtrl >= 0 && oneTopCtrl < 30) {  
  99.             oneTopCtrl++;  
  100.             oneEartRatOut += 3 * sign;  
  101.             if (oneEartRatOut > 360) {  
  102.                 oneEartRatOut %= 360;  
  103.             }  
  104.         }  
  105.     }  
  106.   
  107.     /** 
  108.      * 触屏监听事件 
  109.      */  
  110.     private VelocityTracker mVt = null;  
  111.   
  112.     int detaX = 0// 手指移动的x轴相对位移  
  113.     int tmpX = 0, tmpY = 0// Move时刻坐标点  
  114.   
  115.     int startX = 0, startY = 0;  
  116.     int endX = 0, endY = 0;  
  117.   
  118.     @Override  
  119.     public boolean onTouchEvent(MotionEvent event) {  
  120.         synchronized (event) {  
  121.             int action = event.getAction();  
  122.             switch (action) {  
  123.             case MotionEvent.ACTION_DOWN:  
  124.                 // 手指按下  
  125.                 startX = (int) event.getX();  
  126.                 startY = (int) event.getY();  
  127.                 break;  
  128.             case MotionEvent.ACTION_MOVE:  
  129.                 // 添加采样点  
  130.                 // mVt.addMovement(event);  
  131.                 tmpX = (int) event.getX();  
  132.                 tmpY = (int) event.getY();  
  133.                 break;  
  134.             case MotionEvent.ACTION_UP:  
  135.                 // 手指移动  
  136.                 endX = (int) event.getX();  
  137.                 endY = (int) event.getY();  
  138.                 int tmp = (endX - startX);  
  139.   
  140.                 int dir = judgeDir(startX, startY, endX, endY);  
  141.   
  142.                 if (dir == 1) {// right  
  143.                     if (currentViewNo > 0) {  
  144.                         sign = 1;  
  145.                         oneTopCtrl = 0;  
  146.                         currentViewNo--;  
  147.                     }  
  148.                 } else if (dir == 2) {// left  
  149.                     if (currentViewNo < 3) {  
  150.                         sign = -1;  
  151.                         oneTopCtrl = 0;  
  152.                         currentViewNo++;  
  153.                     }  
  154.                 }  
  155.                 break;  
  156.             case MotionEvent.ACTION_CANCEL:  
  157.             case MotionEvent.ACTION_OUTSIDE:  
  158.                 // 触摸事件结束  
  159.                 // 设置速度的时间单位 1代表每毫秒移动多少像素 1000代表每秒移动多少像素  
  160.                 // 这个方法在获得速度之前必须要设置  
  161.                 mVt.clear();// 清空  
  162.                 mVt.recycle();// 回收vt对象的内存  
  163.                 break;  
  164.             }  
  165.         }  
  166.         return true;  
  167.     }  
  168.   
  169.     /** 
  170.      * 手势方向判别 
  171.      *  
  172.      */  
  173.     private int judgeDir(int startX, int startY, int endX, int endY) {  
  174.   
  175.         if ((endX - startX) > 0 && Math.abs(endX - startX) > screenW / 3) {  
  176.             // 方向是正右方 1  
  177.             return 1;  
  178.         } else if ((endX - startX) < 0 && Math.abs(endX - startX) > screenW / 3) {  
  179.             // 方向是正左方 2  
  180.             return 2;  
  181.         }  
  182.         return 0;  
  183.     }  
  184.   
  185.     @Override  
  186.     public void run() {  
  187.         while (flag) {  
  188.             long start = System.currentTimeMillis();  
  189.             myDraw();  
  190.             logic();  
  191.             long end = System.currentTimeMillis();  
  192.             try {  
  193.                 if (end - start < 50) {  
  194.                     Thread.sleep(50 - (end - start));  
  195.                 }  
  196.             } catch (InterruptedException e) {  
  197.                 e.printStackTrace();  
  198.             }  
  199.         }  
  200.     }  
  201.   
  202.     /** 
  203.      * 画布状态改变监听事件 
  204.      */  
  205.     @Override  
  206.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  207.             int height) {  
  208.   
  209.     }  
  210.   
  211.     /** 
  212.      * 画布被摧毁事件 
  213.      */  
  214.     @Override  
  215.     public void surfaceDestroyed(SurfaceHolder holder) {  
  216.         flag = false;  
  217.     }  
  218.   
  219.     /** 
  220.      * 初始化所用资源 
  221.      */  
  222.     private void initData() {  
  223.         //初始化地球资源  
  224.         bmpEart = (Bitmap) BitmapFactory.decodeResource(getResources(),  
  225.                 R.drawable.revolve_ground);  
  226.         //初始化所有资源坐标  
  227.         initAllXY();  
  228.     }  
  229.     /** 
  230.      * 初始化所有坐标点 
  231.      */  
  232.     private void initAllXY() {  
  233.         bmpEartX = screenW / 2 - bmpEart.getWidth() / 2;  
  234.         bmpEartY = screenH - bmpEart.getHeight() / 4;  
  235.           
  236.         ratX = screenW / 2;  
  237.         ratY = screenH + bmpEart.getHeight() / 4;  
  238.     }  
  239. }  
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1.   
[java] view plaincopyprint?在CODE上查看代码片派生到我的代码片
  1.   
0 0
原创粉丝点击