package com.example.ex4_10; 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.view.KeyEvent; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.RotateAnimation; import android.view.animation.ScaleAnimation; import android.view.animation.TranslateAnimation; public class MyView extends View implements AnimationListener{ private Paint paint; public MyView(Context context) { super(context); paint = new Paint(); paint.setColor(Color.WHITE); paint.setTextSize(20); setFocusable(true); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.pic01); //黑色背景 canvas.drawColor(Color.BLACK); canvas.drawText("方向鍵 ↑ 漸變透明度動畫效果", 80, this.getHeight()-80, paint); canvas.drawText("方向鍵 ↓ 漸變尺寸伸縮動畫效果", 80, this.getHeight()-60, paint); canvas.drawText("方向鍵 → 畫面轉換位置移動動畫效果", 80, this.getHeight()-40, paint); canvas.drawText("方向鍵 ← 畫面轉移旋轉動畫效果", 80, this.getHeight()-20, paint); //繪製位圖,居中 canvas.drawBitmap(bmp, this.getWidth()/2-bmp.getWidth()/2, this.getHeight()/2-bmp.getHeight()/2, paint); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyCode==KeyEvent.KEYCODE_DPAD_UP) { //漸變透明效果 Animation m1 = new AlphaAnimation(0.1f, 1.0f); //設置動畫播放時間爲3秒 m1.setDuration(3000); //啓動動畫效果 this.startAnimation(m1); }else if(keyCode==KeyEvent.KEYCODE_DPAD_DOWN) { //漸變尺寸縮放動畫效果 Animation m2 = new ScaleAnimation(0.0f, 2.0f, 1.5f, 1.5f,Animation.RELATIVE_TO_PARENT,0.5f,Animation.RELATIVE_TO_PARENT,0.0f); m2.setDuration(2000); this.startAnimation(m2); }else if(keyCode==KeyEvent.KEYCODE_DPAD_LEFT) { //移動動畫效果 Animation m3 = new TranslateAnimation(0, 100, 0, 100); m3.setDuration(2000); this.startAnimation(m3); }else if(keyCode==KeyEvent.KEYCODE_DPAD_RIGHT) { //旋轉動畫效果,這裏是旋轉360° Animation m4 = new RotateAnimation(0.0f, 360.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f); m4.setDuration(2000); this.startAnimation(m4); } return super.onKeyDown(keyCode, event); } /** * 動畫開始時響應的函數 */ @Override public void onAnimationStart(Animation animation) { } /** * 動畫結束時響應的函數 */ @Override public void onAnimationEnd(Animation animation) { } /** * 動畫重播時響應的函數 */ @Override public void onAnimationRepeat(Animation animation) { } }
記住,Animation 的每種動畫都是對整個畫布進行操做。html
2.自定義動畫android
(1)動態位圖
在以前隨筆中,曾在屏幕上讓文本字符串跟隨玩家手指移動,從而行程一個動態的效果;那麼讓一張位圖造成動態效果也很容易,只要不斷改變位圖的X或者Y軸的座標便可。下面利用一張位圖造成海的波浪效果。
新建項目,遊戲框架爲SurfaceView 框架,準備圖片water.png以下:canvas
修改MySurfaceView 類,代碼以下:數組
package com.example.ex4_11; 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.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements Callback, Runnable { // 用於控制SurfaceView 的大小、格式等,而且主要用於監聽SurfaceView 的狀態 private SurfaceHolder sfh; // 聲明一張波浪圖 private Bitmap bmp; // 聲明波浪圖的X,Y軸座標 private int bmpX, bmpY; // 聲明一個畫布 private Canvas canvas; // 聲明一個線程 private Thread th; // 線程消亡的標識符 private boolean flag; public MySurfaceView(Context context) { super(context); // 實例SurfaceView sfh = this.getHolder(); // 爲SurfaceView添加狀態監聽 sfh.addCallback(this); } /** * SurfaceView 視圖建立,響應此函數 */ @Override public void surfaceCreated(SurfaceHolder holder) { bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.water); // 讓位圖初始化X軸正好充滿屏幕 bmpX = -bmp.getWidth() + this.getWidth(); // 讓位圖繪製在畫布的最下方,且圖片Y座標正好是(屏幕高-圖片高) bmpY = this.getHeight() - bmp.getHeight(); flag = true; // 實例線程 th = new Thread(this); // 啓動線程 th.start(); } /** * SurfaceView 視圖狀態發生改變時,響應此函數 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * SurfaceView 視圖消亡時,響應此函數 */ @Override public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } private void myDraw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { //刷屏,畫布白色 canvas.drawColor(Color.WHITE); //繪製位圖 canvas.drawBitmap(bmp, bmpX, bmpY, new Paint() ); } } catch (Exception e) { // TODO: handle exception } finally { if (canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } /** * 遊戲邏輯 */ private void logic() { bmpX += 5; } @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 (Exception e) { e.printStackTrace(); } } } }
(2)幀動畫框架
前面是利用改變位圖的X或者Y座標行程動畫效果。固然在遊戲開發中,不少動態的幀數不單單隻有一幀,而所謂幀動畫,其實就是一幀一幀按照必定的順序進行播放實現的。下面是實例演示,效果以下:ide
新建項目,遊戲框架爲 SurfaceView 框架,在項目中導入下面6張png圖片:函數
修改MySurfaceView 類,代碼以下:post
package com.example.ex4_11; 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.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements Callback, Runnable { // 用於控制SurfaceView 的大小、格式等,而且主要用於監聽SurfaceView 的狀態 private SurfaceHolder sfh; // 聲明一個畫布 private Canvas canvas; // 聲明一個線程 private Thread th; // 線程消亡的標識符 private boolean flag; private Paint paint; // 首先聲明6個容量的位圖數組 private Bitmap wifiBmp[] = new Bitmap[6]; // 對應6張圖片的Id private int[] wifiBmpId = new int[] { R.drawable.wifi01, R.drawable.wifi02, R.drawable.wifi03, R.drawable.wifi04, R.drawable.wifi05, R.drawable.wifi06 }; // 記錄當前播放幀 private int currentFrame; public MySurfaceView(Context context) { super(context); // 實例SurfaceView sfh = this.getHolder(); // 爲SurfaceView添加狀態監聽 sfh.addCallback(this); paint = new Paint(); // 畫筆無鋸齒 paint.setAntiAlias(true); // 將幀圖放入幀數組 for (int i = 0; i < wifiBmp.length; i++) { wifiBmp[i] = BitmapFactory.decodeResource(this.getResources(), wifiBmpId[i]); } } /** * SurfaceView 視圖建立,響應此函數 */ @Override public void surfaceCreated(SurfaceHolder holder) { flag = true; // 實例線程 th = new Thread(this); // 啓動線程 th.start(); } /** * SurfaceView 視圖狀態發生改變時,響應此函數 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * SurfaceView 視圖消亡時,響應此函數 */ @Override public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } private void myDraw() { try { canvas = sfh.lockCanvas(); if (canvas != null) { // 刷屏,畫布白色 canvas.drawColor(Color.WHITE); // 繪製位圖,居中顯示 canvas.drawBitmap( wifiBmp[currentFrame], this.getWidth() / 2 - wifiBmp[currentFrame].getWidth() / 2, this.getHeight() / 2 - wifiBmp[currentFrame].getHeight() / 2, paint); } } catch (Exception e) { // TODO: handle exception } finally { if (canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } /** * 遊戲邏輯 */ private void logic() { currentFrame++; // 當播放的當前幀大於而且等於幀數組時,重置當前幀爲0 if (currentFrame >= wifiBmp.length) { currentFrame = 0; } } @Override public void run() { while (flag) { long start = System.currentTimeMillis(); myDraw(); logic(); long end = System.currentTimeMillis(); try { if (end - start < 500) { Thread.sleep(500 - (end - start)); } } catch (Exception e) { e.printStackTrace(); } } } }
(3)剪切圖動畫動畫
剪切圖動畫相似於幀動畫的形式,惟一的區別就是動態幀所有放在了一張圖片中,而後經過設置可視區域完成。簡單的解釋,繪圖時經過控制X軸或者Y軸座標,來逐幀顯示要顯示的圖片部分,達到動態的效果。下面是實例,運行效果和前面的幀動畫同樣。步驟以下:this
新建項目,遊戲框架爲 SurfaceView 框架,在項目中導入下面這張png圖片:
修改MySurfaceView 類,代碼以下:
package com.example.ex4_11; 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.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; public class MySurfaceView extends SurfaceView implements Callback, Runnable { // 用於控制SurfaceView 的大小、格式等,而且主要用於監聽SurfaceView 的狀態 private SurfaceHolder sfh; // 聲明一個畫布 private Canvas canvas; // 聲明一個線程 private Thread th; // 線程消亡的標識符 private boolean flag; private Paint paint; // 建立位圖 private Bitmap bmp = BitmapFactory.decodeResource(this.getResources(), R.drawable.wifi_all); // 記錄當前播放幀 private int currentFrame; public MySurfaceView(Context context) { super(context); // 實例SurfaceView sfh = this.getHolder(); // 爲SurfaceView添加狀態監聽 sfh.addCallback(this); paint = new Paint(); // 畫筆無鋸齒 paint.setAntiAlias(true); } /** * SurfaceView 視圖建立,響應此函數 */ @Override public void surfaceCreated(SurfaceHolder holder) { flag = true; // 實例線程 th = new Thread(this); // 啓動線程 th.start(); } /** * SurfaceView 視圖狀態發生改變時,響應此函數 */ @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } /** * SurfaceView 視圖消亡時,響應此函數 */ @Override public void surfaceDestroyed(SurfaceHolder holder) { flag = false; } private int minW = bmp.getWidth() / 6; private void myDraw() { try { //居中點X軸座標 int cW = this.getWidth() / 2 - minW / 2; //居中點Y軸座標 int cH = this.getHeight() / 2 - bmp.getHeight() / 2; canvas = sfh.lockCanvas(); if (canvas != null) { // 刷屏,畫布白色 canvas.drawColor(Color.WHITE); canvas.save(); // 設置畫布的可視區域,大小爲每幀的大小,居中 canvas.clipRect(cW, cH, cW + minW, cH + bmp.getHeight()); // 繪製位圖,居中 canvas.drawBitmap(bmp, cW - currentFrame * minW, cH, paint); canvas.restore(); } } catch (Exception e) { // TODO: handle exception } finally { if (canvas != null) { sfh.unlockCanvasAndPost(canvas); } } } /** * 遊戲邏輯 */ private void logic() { currentFrame++; // 當播放的當前幀大於而且等於幀數組時,重置當前幀爲0 if (currentFrame >= 6) { currentFrame = 0; } } @Override public void run() { while (flag) { long start = System.currentTimeMillis(); myDraw(); logic(); long end = System.currentTimeMillis(); try { if (end - start < 500) { Thread.sleep(500 - (end - start)); } } catch (Exception e) { e.printStackTrace(); } } } }