求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
Android手机游戏开发知识点总结
 
发布于2013-8-9
 

第一部分 其实游戏就是让状态机不断的让Canvas在View上画你想要的东西。这个状态机包括内部的执行,还包括外部的输入。

Android开发的MVC模式

1,通过View和SurfaceView来显示界面的视图。(处理界面与用户的交互事件,如,触笔点击,用户按键等。可通过View类的onKeyDown,onKeyUp,onTouchEvent等)。

2,用Activity来控制游戏的整体结构。

3,设计一个逻辑类,用来处理逻辑运算。

Android中任何一个View类都只有重写onDraw方法来实现界面显示。

Android中提供了onKeyUp,onKeyDown,onKeyMultiple,onKeyPreIme,onTouchEvent,onTrackballEvent等方法。可以用来处理游戏中的事件消息。所以继承View时,需要重载这些方法。

Android中提供了invalidate来刷新界面,但invalidate不能直接在线程中调用,违背单线程模型。

因此Android中最常用的方法是利用Handler来时更新UI界面。

第一部分 View 类

每个View类都有一个绘画的画布,在游戏中可以自定义视图View,任何一个View类都只需要重写onDraw方法来实现界面显示,可以是3D,也可以是文本。

游戏的核心就是不断的绘图和刷新,图我们可以通过onDraw方法绘制,刷新Android中可以用invalidate方法来刷新界面,注意:invalidate不能直接在线程中调用,因其违背了 单线程模型。因此Android中最常用的方法是利用Handler来时更新UI界面。下面这个例子中包含了两个刷新方法。

public class Game extends Activity{
    public static final int REFRESH = 1;
    public GameView gameView;
    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     this.gameView = new GameView(this);//实例化GameView
     setContentView(gameView);
     new Thread(new GameThread()).start();
    }public class Game extends Activity{
    public static final int REFRESH = 1;
    public GameView gameView;
    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     this.gameView = new GameView(this);//实例化GameView
     setContentView(gameView);
     new Thread(new GameThread()).start();
    }

// Handler handler = new Handler(){//注释掉的为实例化Handler对象并重写handleMessage方法实现一个消息接受器,然后在线程中通过sendMessage方法发送更新界面的消息,当接收器收到更新界面的消息时,便执行invalidate方法更新屏幕显示。

 // public void handleMessage(Message msg){//接受消息
   //  switch (msg.what){
   //    case Game.REFRESH:
   //    gameView.invalidate();//更新界面
   //    break;
   //   }
   //   super.handleMessage(msg);
   //  }
   // };
    public boolean onTouchEvent (MotionEvent event){
     return true;  
    }
    public boolean onKeyDown(int keyCode,KeyEvent event){
     return true; 
    }
    public boolean onKeyUp(int keyCode,KeyEvent event){
     switch (keyCode){
      case KeyEvent.KEYCODE_DPAD_DOWN:
       gameView.y+=6;
       break;
      case KeyEvent.KEYCODE_DPAD_UP:
       gameView.y-=6;
       break;
     }
     return true;
    }
    public boolean onKeyMultiple(int keyCode,int repeatCount,KeyEvent event){
     return true;
    }
    
  // public class GameThread implements Runnable{//创建更新线程
  //  @Override
  //  public void run() {
  //   while(!Thread.currentThread().isInterrupted()){
  //    Message message = new Message();
  //    message.what = Game.REFRESH;
  //    Game.this.handler.sendMessage(message);//发送消息
  //    try{
  //     Thread.sleep(100);
  //    }catch(InterruptedException e){
  //     Thread.currentThread().interrupt();
  //    }
  //   }
  //  }
  // }

   public class GameThread implements Runnable{
    public void run(){
     while(!Thread.currentThread().isInterrupted()){
      try{
      Thread.sleep(100);
      }catch(InterruptedException e){
       Thread.currentThread().interrupt();
      }
      gameView.postInvalidate();//使用PostInvalidate可以直接在线程中更新界面 不需要Handler来传递消息
     } 
    }
   }
   }
   
   public class GameView extends View{
    public int count = 0;
    public int y =0;
    public GameView(Context context) {
     super(context);
    }
    public void onDraw(Canvas canvas){
     if(count<8){
      count++;
     }else{
      count=0;
     }
     Paint paint= new Paint();
     switch(count%4){
      case 0:
       paint.setColor(Color.BLACK);
       break;
      case 1: 
       paint.setColor(Color.RED);
       break;
      case 2: 
       paint.setColor(Color.YELLOW);
       break;
      case 3: 
       paint.setColor(Color.GREEN);
       break;
     }
     canvas.drawRect(y,y,y+40,y+40, paint);//绘制矩形
    }
   }

第二部分 SurfaceView类

1,开发复杂游戏,而且对程序的执行效率要求更高时用此类,因本身就是双缓冲机制的。

2,SurfaceView可以直接访问一个画布。

3,SurfaceView是提供给需要直接画像素而不是使用窗体部件的应用而使用的。

4,View即其子类(如TextVie,Button)要画在Surface上。每个Surface创建一个Canvas对象(属性时常改变)用来管理View在Surface上绘制操作。

5,使用SurfaceView绘图时,一般都是出现在最顶层。在使用时要对其创建,销毁,情况改变进行监视,这就需要实现SurfaceHolder.Callback接口,
如果要对被绘制的画布进行裁剪,控制其大小时都需要使用SurfaceHolder来完成处理。

6,在程序中,SurfaceHolder对象需要通过getHolder方法来获得,同时还需要addCallback方法来添加“回调函数”。

7,SurfaceView与View不同之处,在于SurfaceView不需要通过线程来更新视图,在绘制前必须使用lockCanvas方法锁定画布,并得到画布,然后在画布上绘制完成后,使用unlockCanvasAndPost方法来解锁画布。

8,addCallback:给SurfaceView添加一个回调函数;removeCallback:从SurfaceView移除回调函数;

public class GameView2 extends SurfaceView implements SurfaceHolder.Callback, Runnable{
    SurfaceHolder surfaceHolder = null;//定义对象
    public boolean loop = false;
    public int count = 1;
    public GameView2(Context context) {
     super(context);
     surfaceHolder = this.getHolder();//实例化SurfaceHolder对象
     surfaceHolder.addCallback(this);//添加回调函数
     loop = true;
     this.setFocusable(true);//不知道这句什么意思?
    }
    private void Draw() {
     Canvas canvas = surfaceHolder.lockCanvas();//锁定画布
     if(surfaceHolder ==null||canvas ==null){
      return ;
     }
     if(count<100){
      count++;
     }else{
      count= 0;
     }
     Paint paint = new Paint();//创建画笔
     paint.setAntiAlias(true);//设置抗锯齿
     paint.setColor(Color.GREEN);//设置画笔颜色 
     canvas.drawRect(0,0,320,480, paint);//绘制矩形 
     switch(count%4){
      case 0:
       paint.setColor(Color.BLUE);
       break;
      case 1:
       paint.setColor(Color.YELLOW);
       break;
      case 2:
       paint.setColor(Color.RED);
       break;
      case 3:
       paint.setColor(Color.CYAN);
       break;
      default:
       paint.setColor(Color.WHITE);
       break;
     }
     canvas.drawCircle(130, 240, 500, paint);
     surfaceHolder.unlockCanvasAndPost(canvas);//绘制后解锁,绘制后必须解锁才能显示 
    }
    @Override//在Surface大小发生改变时激发
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
     // TODO Auto-generated method stub  
    }
    @Override//在Surface创建时激发
    public void surfaceCreated(SurfaceHolder holder) {
     // TODO Auto-generated method stub
     new Thread(this).start();
    }
    @Override//在Surface销毁时调用
    public void surfaceDestroyed(SurfaceHolder holder) {
     // TODO Auto-generated method stub
     loop=false;
    }
    public void run(){
     while(loop){
      try{
       Thread.sleep(200);
       synchronized (surfaceHolder) {
        Draw();
       }
      }catch(Exception e){
      }
     }
    }
   }

第三部分 Paint类和Color类

在Android中通过graphic类来显示2D图形。graphic包括Canvas类(画布),Paint(画笔),Color(颜色),Bitmap(图像),2D几何图形等常用类。

package graphics;

Paint类常用的一些方法:

setAntiAlias 设置画笔的锯齿效果

setColor 设置画笔颜色

setARGB 设置画笔的a,r,g,b值。

setAlpha 设置透明度

setTextSize 设置字体大小

setStyle 设置画笔风格 空心或实心

setStrokeWidth设置空心的边框宽度

getColor 得到画笔的颜色

getAlpha 得到画笔的透明度

Color类中定义了一些颜色常量

Color.rgb方法将整型的颜色转换成Color类型。如Color.red方法可提取出红色的值。

 /**
   * 注意:在绘制时按从上到下的顺序绘制的 ,后面的如果和前面的重合的话会将前面的覆盖掉
   */
   public class Graphics_Paint_Color extends View implements Runnable {
    public Paint paint;
    private String TAG="你好";
    public Graphics_Paint_Color(Context context) {
     super(context);
     paint = new Paint();//创建画笔
     new Thread(this).start();//开启线程
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     paint.setAntiAlias(true);//设置抗锯齿
     paint.setColor(Color.RED);//设置画笔颜色
     paint.setColor(Color.rgb(12, 234, 34));//设置画笔颜色 其中参数分别为red,green,blue三种颜色的值
  
     Color.red(23);//提取颜色?
     Color.blue(234);
  
     paint.setARGB(255, 23,234,49);//设置Paint的颜色和Alpha值
  
     paint.setAlpha(200);//设置透明度
  
    //paint.set(new PAINT());//设置另外一个Paint对象 
     paint.setTextSize(14);//设置字体的尺寸
   
     //得到Paint的一些属性
     Log.i(TAG, "paint的颜色"+paint.getColor());
     Log.i(TAG,"paint的Alpha"+paint.getAlpha());
  
     paint.setStyle(Paint.Style.STROKE);//设置Paint为空心
     paint.setStrokeWidth(5);//设置空心的外框宽度
     canvas.drawRect(0,0,50,60, paint);//绘制空心矩形
  
     paint.setStyle(Paint.Style.FILL);//设置Paint为实心
     canvas.drawRect(60,70,120,140, paint);//绘制实心的矩形 
    }
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(200);
      }catch(Exception e){
       e.printStackTrace();
       Thread.currentThread().interrupt();
      }
      postInvalidate();//使用postInvalidate可以直接在线程中更新界面
     }
    }
   }

在View或SurfaceView中绘制图形后,需要在Activtiy中通过setContentView()来让其显示出来

第四部分 Canvas类和ShadeDrawable类

Canvas方法:

Canvas() 创建画布,可以用setBitmap()方法设置绘制具体画布

Canvas(Bitmap bitmap) 以bitmap对象创建一个画布,则将内容都绘制在bitmap上,所以bitmap不得为null

Canvas(GL gl) 绘制3D效果时使用,与OpenGL

drawColor 设置画布背景色

setBitmap 设置具体画布

clipRect 设置显示区域,即设置裁剪区

isOpaque 检测是否支持透明

rotate 旋转画布 在游戏中我们需要对精灵旋转,缩放或其它操作就可以通过旋转画布来实现,但在旋转画布时会旋转画布上所以对象,而我们只需要旋转其中一个。这个时候我们就需要用save方法来锁定需要操作的对象,在操作后通过restore方法来解锁。(例子有此方法的运用)

setViewport 设置画布中显示窗口

skew 设置便宜量

绘制几何图形的方法

drawRect 绘制矩形

drawCircle 绘制圆形

drawOval 绘制椭圆

drawLine 绘制直线

drawPoint 绘制点

public class CanvasView extends View implements Runnable{
    private Paint paint ;
    public ShapeDrawableView shapeDrawableView;
    public CanvasView(Context context) {
     super(context);
     paint = new Paint();
     shapeDrawableView= new ShapeDrawableView(context);//得到对象
     new Thread(this).start();
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawColor(Color.BLACK);//设置画布颜色
     paint.setAntiAlias(true);//取消抗锯齿效果
     //canvas.clipRect(20,20,80,80);//设置裁剪区域
  
     canvas.save();//锁定画布
     //canvas.rotate(45.0f);//旋转画布
     paint.setColor(Color.RED);//设置颜色及绘制矩形
     canvas.drawRect(new Rect(10,10,80,80), paint);
     canvas.restore();//解锁画布
 
     paint.setStyle(Paint.Style.STROKE);{//设置为空心画笔 
      Rect rect = new Rect();
       rect.left =85;
       rect.bottom=80;
       rect.right=150;
       rect.top = 10;
      paint.setColor(Color.BLUE);
      canvas.drawRect(rect, paint);//绘制矩形   
      canvas.drawCircle(60,60,50,paint);//绘制圆形
   
      RectF rectF = new RectF();//绘制椭圆
       rectF.bottom=80;
       rectF.left=160;
       rectF.right= 300;
       rectF.top = 10;
      canvas.drawOval(rectF, paint);
   
      Path path = new Path();//绘制多边形
       path.moveTo(10, 90);
       path.lineTo(80, 100);
       path.lineTo(70,150);
       path.lineTo(10, 200);
       path.close();//封闭多边形
      canvas.drawPath(path, paint);
   
      paint.setStrokeWidth(5);
      canvas.drawLine(50,50,300,200, paint);
     }
     paint.setStyle(Paint.Style.FILL);{//设置画笔为实心
      paint.setColor(Color.YELLOW);
      canvas.drawRect(20,250,300,300, paint);
     }  
     shapeDrawableView.DrawShape(canvas);//绘制另一View里的图形到本View中来
    }
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(200);
      }catch(Exception e){
       Thread.currentThread().interrupt();
      }
      postInvalidate();//直接在线程中更新
     }
    }
   }

   /**
   *Android中可以通过ShapeDrawable来绘制图像。可以通过getPaint方法得到Paint对象,
    setBounds 此方法可设置图形显示的区域
    通过ShapeDrawable的Draw方法将图形画到屏幕上
   */
   public class ShapeDrawableView extends View{
    ShapeDrawable shapeDrawable;
    Paint paint;
    public ShapeDrawableView(Context context) {
    super(context);
    }
    public void DrawShape(Canvas canvas){
     shapeDrawable = new ShapeDrawable();//------用ShapeDrawable绘图必须要实例化对象
     paint=shapeDrawable.getPaint();//得到画笔
     paint.setColor(Color.GREEN);//设置画笔颜色
     Rect bounds =new Rect(10,310,80,390);//绘制矩形
     shapeDrawable.setBounds(bounds);//------用ShapeDrawable绘图必须要使用SetBounds显示区域
     shapeDrawable.draw(canvas);//--------用ShapeDrawable绘图必须要使用draw()使图像显示到屏幕上 
     //另一种写法
     /* 实例化ShapeDrawable对象并说明是绘制一个椭圆 */
     shapeDrawable = new ShapeDrawable(new OvalShape());
     //得到画笔paint对象并设置其颜色
     shapeDrawable.getPaint().setColor(Color.GREEN);
     /* 设置图像显示的区域 */
     shapeDrawable.setBounds(70, 250, 150, 280);
     /* 绘制图像 */
     shapeDrawable.draw(canvas);
  
     //以下为绘制多边形
     Path path1 = new Path();
     /*设置多边形的点*/
     path1.moveTo(150+5, 80+80-50);
     path1.lineTo(150+45, 80+80-50);
     path1.lineTo(150+30, 80+120-50);
     path1.lineTo(150+20, 80+120-50);
     /* 使这些点构成封闭的多边形 */
     path1.close();
     //PathShape后面两个参数分别是宽度和高度
     shapeDrawable = new ShapeDrawable(new PathShape(path1,150,150));
     //得到画笔paint对象并设置其颜色
     shapeDrawable.getPaint().setColor(Color.BLUE);
     /* 设置图像显示的区域 */
     shapeDrawable.setBounds(100, 170, 200, 280);
     /* 绘制图像 */
     shapeDrawable.draw(canvas);
    }
   }

第五部分 字符串绘制

Android中提供了drawText方法来绘制字符串,在绘制执法串之前需要设置画笔对象,包括字符串的尺寸,颜色等属性。使用FontMetrics来规划字体属性

可以用getFontMetrics方法来获得系统字体的相关内容。

setTextSize 设置字符串的尺寸

setARGB 设置颜色

getTextWidths 取得字符串宽度

setFlags(Paint.ANTI_ALIAS_FLAG) 消除锯齿

measureText 得到字符串宽度

得到字符串高度可用:

FontMetrics fontMetrics = paint.getFontMetrics();

textselfHeight = (int)Math.ceil(fontMetrics.descent - fontMetrics.top)+2;//得到文字的高度

textPageLineNum = textHeight/textselfHeight;//每一页的行数 = 绘制区域的高度/文字本身的高度

下例实现了文本翻页,换行。

* 实现文字自动换行
   * 自动翻页
   public class TextUtil{
    int  m_iTextPosX; //绘制的x点
    int  m_iTextPosY; //绘制的y点
    int  m_iTextWidth; //绘制宽度
    int  m_iTextHeight; //绘制高度
    int  m_iFontHeight; //字体高度
    int  m_ipageLineNum; //每一页显示的行数
    int  m_iTextBGColor; // 背景颜色
    int  m_iTextColor; // 字体颜色
    int  m_iAlpha;  //Alpha值
    int  m_iRealLine; // 字符串真实的行数
    int  m_iCurLine;  //当前行
    
    String m_strText;  
    Vector m_String;
    Paint m_paint;
    int  m_iTextSize;
    public TextUtil(){
     m_paint = new Paint();
     m_String = new Vector();
    }
    public TextUtil(String strText, int x, int y, int w, int h, int bgcolor, int txetcolor, int a, int iTextSize){
     m_paint = new Paint();
     m_String = new Vector();
     
     m_strText = strText;
     m_iTextPosX = x;
     m_iTextPosY = y;
     m_iTextWidth = w;
     m_iTextHeight = h;

     m_iTextBGColor = bgcolor;
     m_iTextColor = txetcolor;
     m_iTextSize = iTextSize;
     m_iAlpha = a;

    }
   /**
   * 初始化
   * @param strText 要显示的字符串
   * @param x   x
   * @param y   y
   * @param w   w
   * @param h   h 
   * @param bgcolor 背景颜色
   * @param txetcolor 文字的颜色
   * @param a   Alpha
   * @param iTextSize 字体大小
   */
    public void InitText(String strText, int x, int y, int w, int h, int bgcolor, int txetcolor, int a, int iTextSize){
     m_iCurLine = 0;
     m_ipageLineNum = 0;
     m_iRealLine = 0;
     m_strText = "";
     m_iTextPosX = 0;
     m_iTextPosY = 0;
     m_iTextWidth = 0;
     m_iTextHeight = 0;
     m_iTextBGColor = 0;
     m_iTextColor = 0;
     m_iTextSize = 0;
     m_iAlpha = 0;

     m_String.clear();

     SetText(strText);
     SetRect(x, y, w, h);
     SetBGColor(bgcolor);
     SetTextColor(txetcolor);
     SetFontSize(iTextSize);
     SetAlpha(a);

     SetPaint();
     GetTextIfon();
    }
   /**
   * 设置Alpha
   * @param a Alpha值
   */
    public void SetAlpha(int a){
     m_iAlpha = a;
    }
   /**
   * 对Paint属性的设置
   */
    public void SetPaint(){
     m_paint.setARGB(m_iAlpha, Color.red(m_iTextColor), Color.green(m_iTextColor), Color.blue(m_iTextColor));
     m_paint.setTextSize(m_iTextSize);
    }
   /**
   * 设置字体尺寸
   * @param iTextSize
   */
    public void SetFontSize(int iTextSize){
     m_iTextSize = iTextSize;
    }
   /**
   * 设置显示文本的区域
   * @param x
   * @param y
   * @param w
   * @param h
   */
    public void SetRect(int x, int y, int w, int h){
     m_iTextPosX = x;
     m_iTextPosY = y;
     m_iTextWidth = w;
     m_iTextHeight = h;
    }
   /**
   * 设置背景颜色
   * @param bgcolor
   */
    public void SetBGColor(int bgcolor){
     m_iTextBGColor = bgcolor;
    }
   /**
   * 设置字体颜色
   * @param txetcolor
   */
    public void SetTextColor(int txetcolor){
     m_iTextColor = txetcolor;
    }
   /**
   * 色绘制要显示的字符串
   * @param strText
   */
    public void SetText(String strText){
     m_strText = strText;
    }
   /**
   * 得到字符串的信息
   * 包括:行数、页数等信息
   * 内部调用
   */
    public void GetTextIfon(){
     char ch;
     int w = 0;
     int istart = 0;
     FontMetrics fm = m_paint.getFontMetrics(); 
     m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + 2;
     m_ipageLineNum = m_iTextHeight / m_iFontHeight;
      for (int i = 0; i < m_strText.length(); i++){
       ch = m_strText.charAt(i);
       float[] widths = new float[1];
       String srt = String.valueOf(ch);
       m_paint.getTextWidths(srt, widths);
        if (ch == '\n'){
         m_iRealLine++;
         m_String.addElement(m_strText.substring(istart, i));
         istart = i + 1;
         w = 0;
        }else{
         w += (int) (Math.ceil(widths[0]));
         if (w > m_iTextWidth){
          m_iRealLine++;
          m_String.addElement(m_strText.substring(istart, i));
          istart = i;
          i--;
          w = 0;
         }else{
          if (i == (m_strText.length() - 1)){
           m_iRealLine++;
           m_String.addElement(m_strText.substring(istart, m_strText.length()));
          }
         }
        }
      }
    }
   /**
   * 绘制字符串
   * @param canvas
   */
    public void DrawText(Canvas canvas){
     for (int i = m_iCurLine, j = 0; i < m_iRealLine; i++, j++){
      if (j > m_ipageLineNum){
       break;
      }
      canvas.drawText((String) (m_String.elementAt(i)), m_iTextPosX, m_iTextPosY + m_iFontHeight * j, m_paint);
     }
    }
   /**
   * 翻页等按键处理
   * @param keyCode
   * @param event
   * @return
   */
    public boolean KeyDown(int keyCode, KeyEvent event){
     if (keyCode == KeyEvent.KEYCODE_DPAD_UP){
      if (m_iCurLine > 0){
       m_iCurLine--;
      }
     }else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
      if ((m_iCurLine + m_ipageLineNum) < (m_iRealLine - 1)){
       m_iCurLine++;
      }
     }
     return false;
    }
   }

   public class GameView extends View implements Runnable{
    /* 声明Paint对象 */
    private Paint mPaint = null;
    private int   mICount = 0; 
    /* 声明TextUtil对象 */
    private TextUtil mTextUtil = null;
    public GameView(Context context){
     super(context);
     /* 构建对象 */
     mPaint = new Paint(); 
     String string = "测试自动换行\n\n设置文字自动换行abcdefgh\niklmnopqrst换行123347465\n43756245Android\n设置文字自动换行abcdefgh\n
        iklmnopqrst换行123347465\n43756245Android"; 
     /* 实例化TextUtil */
     mTextUtil = new TextUtil(string,5,50,300,80,0x0,0xffffff,255,16);
     /* 初始化TextUtil */
     mTextUtil.InitText(string,5,150,300,80,0x0,0xffffff,255,16);
     /* 开启线程  */
     new Thread(this).start();
    } 
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     /* 设置背景颜色 */
     canvas.drawColor(Color.BLACK);
     mPaint.setAntiAlias(true);
     if ( mICount < 100 ){
      mICount++;
     }
     mPaint.setColor(Color.RED);
     canvas.drawText("装在进度:"+mICount+"%......", 10, 20, mPaint);
     /* 绘制TextUtil:实现自动换行 */
     mTextUtil.DrawText(canvas);
    }
    // 触笔事件
    public boolean onTouchEvent(MotionEvent event){
     return true;
    }
    // 按键按下事件
    public boolean onKeyDown(int keyCode, KeyEvent event){
     return mTextUtil.KeyDown(keyCode, event);
    }
    // 按键弹起事件
    public boolean onKeyUp(int keyCode, KeyEvent event){
     return false;
    }
    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
     return true;
    } 
   /**
   * 线程处理
   */
    public void run(){
     while (!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(100);
      }catch (InterruptedException e){
       Thread.currentThread().interrupt();
      }
       //使用postInvalidate可以直接在线程中更新界面
       postInvalidate();
     }
    }
   }
   
   public class Activity01 extends Activity{
    private GameView mGameView = null;

    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
     mGameView = new GameView(this);
     setContentView(mGameView);
    }
    // 按键弹起事件
    public boolean onKeyUp(int keyCode, KeyEvent event){
     return super.onKeyUp(keyCode, event);
    }
    // 按键按下事件
    public boolean onKeyDown(int keyCode, KeyEvent event){
     mGameView.onKeyDown(keyCode, event);
     return true;
    }
   }

第六部分 图像的绘制 旋转 缩放

1.((BitmapDrawable) getResource().getDrawable(资源索引)).getBitmap() 加载资源

2.canvas.drawBitmap(bitmap,x,y,null);将bitmap绘制在屏幕的(x,y)位置

3.getHeight() ,getWidth() 获得图片的高度好宽度

4.Android中通过Matrix旋转图片。Matrix没有结果体,它必须被实例化,可通过reset方法或set方法来实现。

setRotate方法来设置旋转角度

createBitmap 创建一个经过旋转等处理的Bitmap对象

5.Matrix的postScale(x,y)方法来设置缩放的倍数 分别在x,y方法缩放的倍数。

public class Draw_Bitmap extends Activity{
    public DrawBitmap drawBitmap;
    public void onCreate(Bundle savedInstanceState){
     drawBitmap = new DrawBitmap(this);
     super.onCreate(savedInstanceState);
     setContentView(drawBitmap);
    }
    public boolean onKeyDown(int keyCode,KeyEvent event){
     if(drawBitmap == null){
      return false;
     }else if(keyCode ==KeyEvent.KEYCODE_BACK){
      this.finish();
      return true;
     }
     return drawBitmap.onKeyDown(keyCode, event); 
    }
   }
 
   public class DrawBitmap extends View implements Runnable{
    private static Paint paint1=null;
    public static Bitmap dog1=null;
    public Bitmap tb1=null;
    public int dog1width = 0;
    public int dog1height = 0;
    public float rotate=0.0f;
    public float scale = 1.0f;
 
    Matrix matrix = new Matrix();//构建Matrix对象 Matrix用于旋转图片

    public DrawBitmap(Context context) {
     super(context);
     paint1 = new Paint();
     //从资源中装载图片
     dog1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.dog)).getBitmap();
     tb1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.tb)).getBitmap();
  
     dog1width = dog1.getWidth();//得到图像的宽度
     dog1height =dog1.getHeight();//得到图像的高度
  
     new Thread(this).start();//创建,开启线程
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawColor(Color.BLUE);
     canvas.drawBitmap(dog1,10,240,paint1);
  
     matrix.reset();//重置matrix得到Matrix的方法体
     matrix.setRotate(rotate);//设置旋转
     matrix.postScale(scale, scale);//设置缩放分别为(x,y)方法的缩放
     Bitmap dog1rotate = Bitmap.createBitmap(dog1,0,0,dog1width,dog1height,matrix,true);//按Matrix的旋转构建新的Bitmap
     DrawBitmap.drawImage(canvas,dog1rotate,130,240);//绘制旋转后的图片
  
     dog1rotate= null;//这里难道是释放资源
  
     DrawBitmap.drawImage(canvas,dog1,0,0);//在屏幕的(0,0)处绘制图片
     DrawBitmap.drawImage2(canvas,tb1,10,dog1.getHeight(),142,100,150,178);//在指定位置按指定的裁决区域进行绘制
    }
   /**
   * i---屏幕上的x坐标
   * height---屏幕上的y坐标
   * j---要绘制图片的宽度
   *k---要绘制图片的高度
   *l---图片上的x坐标
   *m---图片上的Y坐标
   */
    private static void drawImage2(Canvas canvas, Bitmap tb12, int i,
              int height, int j, int k, int l, int m) {
     Rect rect1 = new Rect();//图片上裁剪区域
      rect1.left = l;
      rect1.top =m;
      rect1.right=l+j;
      rect1.bottom = m+k;
  
     Rect rect2 = new Rect();//屏幕上的裁剪区域
      rect2.left = i;
      rect2.top = height;
      rect2.right =i+j;
      rect2.bottom = height+k;
     canvas.drawBitmap(tb12, rect1,rect2, null);
    }
    private static void drawImage(Canvas canvas, Bitmap dog12, int i, int j){
     canvas.drawBitmap(dog12,i,j,null);
    } 
    public boolean onKeyDown(int keyCode,KeyEvent event){
     if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
      rotate+=10;
     }else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
      rotate--;
     }else if(keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
      if(scale>0.3){//注意:scale必须大于0,否则会报错
       scale-=0.1;
      }
     }else if(keyCode == KeyEvent.KEYCODE_DPAD_UP){
      if(scale<2.0){
       scale+=0.1;
      }
     }
     return true; 
    }
    public boolean onKeyUp(int keyCode,KeyEvent event){
     return false;
    }
    public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
     return true;
    }
    @Override
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(100);
      }catch(Exception e){
       Thread.currentThread().interrupt();
      }
       postInvalidate();
     }
    }
   }


第七部分 图像像素的操作

Android中Bitmap提供了操作像素的方法,可通过getPixels方法获得图像像素并放到一个数组中去。我们处理这个数组就可以了,最后通过setPixels设置这个像素数组到Bitmap中去。

Android中,每一个图像像素通过4字节整数来展现:最高位字节用作Alpha通道。即用来实现透明与不透明控制,255代表完全透明,0为完全不透明;接下来的一个字节是Red红色通道。

255代表完全是红色。依次类推,接下来的两个字节相应地实现绿色和蓝色通道。

下例为通过图像像素的操作来模拟水纹效果。

 public class GameView extends View implements Runnable{
    int BACKWIDTH;
    int BACKHEIGHT;
    short[] buf2;
    short[] buf1;
    int[] Bitmap2;
    int[] Bitmap1;  
   public GameView(Context context){
    super(context); 
    Bitmap  image = BitmapFactory.decodeResource(this.getResources(),R.drawable.qq);//装载图片
    BACKWIDTH = image.getWidth();
    BACKHEIGHT = image.getHeight();
     
    buf2 = new short[BACKWIDTH * BACKHEIGHT];
    buf1 = new short[BACKWIDTH * BACKHEIGHT];
    Bitmap2 = new int[BACKWIDTH * BACKHEIGHT];
    Bitmap1 = new int[BACKWIDTH * BACKHEIGHT];

    image.getPixels(Bitmap1, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT);//加载图片的像素到数组中  
    new Thread(this).start();
   }
   public void DropStone(
    int x,    // x坐标
    int y,    // y坐标
    int stonesize,  // 波源半径
    int stoneweight){ // 波源能量   
    for (int posx = x - stonesize; posx < x + stonesize; posx++)
     for (int posy = y - stonesize; posy < y + stonesize; posy++)
      if ((posx - x) * (posx - x) + (posy - y) * (posy - y) < stonesize * stonesize)
      buf1[BACKWIDTH * posy + posx] = (short) -stoneweight;
   }   
   public void RippleSpread(){
    for (int i = BACKWIDTH; i < BACKWIDTH * BACKHEIGHT - BACKWIDTH; i++){   
     buf2[i] = (short) (((buf1[i - 1] + buf1[i + 1] + buf1[i - BACKWIDTH] + buf1[i + BACKWIDTH]) >> 1) - buf2[i]);// 波能扩散  
     buf2[i] -= buf2[i] >> 5;// 波能衰减
    }
    // 交换波能数据缓冲区
    short[] ptmp = buf1;
    buf1 = buf2;
    buf2 = ptmp;
   }
   public void render(){//渲染你水纹效果 
    int xoff, yoff;
    int k = BACKWIDTH;
    for (int i = 1; i < BACKHEIGHT - 1; i++){
     for (int j = 0; j < BACKWIDTH; j++){
      // 计算偏移量
      xoff = buf1[k - 1] - buf1[k + 1];
      yoff = buf1[k - BACKWIDTH] - buf1[k + BACKWIDTH];
      // 判断坐标是否在窗口范围内
      if ((i + yoff) < 0){
       k++;
       continue;
      }
      if ((i + yoff) > BACKHEIGHT){
       k++;
       continue;
      }
      if ((j + xoff) < 0){
       k++;
       continue;
      }
      if ((j + xoff) > BACKWIDTH){
       k++;
       continue;
      }
      // 计算出偏移象素和原始象素的内存地址偏移量
      int pos1, pos2;
      pos1 = BACKWIDTH * (i + yoff) + (j + xoff);
      pos2 = BACKWIDTH * i + j;
      Bitmap2[pos2++] = Bitmap1[pos1++];
      k++;
     }
    }
   }  
   public void onDraw(Canvas canvas){
    super.onDraw(canvas); 
    canvas.drawBitmap(Bitmap2, 0, BACKWIDTH, 0, 0, BACKWIDTH, BACKHEIGHT, false, null);//绘制经过处理的图片效果
   } 
   public boolean onTouchEvent(MotionEvent event){// 触笔事件  
    return true;
   }
   public boolean onKeyDown(int keyCode, KeyEvent event){// 按键按下事件
    return true;
   }
   public boolean onKeyUp(int keyCode, KeyEvent event){// 按键弹起事件
    DropStone(BACKWIDTH/2, BACKHEIGHT/2, 10, 30);
    return false;
   }
   public boolean onKeyMultiple(int keyCode, int repeatCount, KeyEvent event){
    return true;
   }
   public void run(){//线程处理
    while (!Thread.currentThread().isInterrupted()){
     try{
      Thread.sleep(50);
     }catch (InterruptedException e){
      Thread.currentThread().interrupt();
     }
      RippleSpread();
      render();
     //使用postInvalidate可以直接在线程中更新界面
     postInvalidate();
    }
   }
   }

第八部分 Shader类 图片的渲染

所谓的渲染就是对画笔的设置 本人是这样理解的。Shader类的使用,都需要先构建Shader对象,然后通过Paint的setShader方法来设置渲染对象,然后在绘制时使用Paint对象。当然用不同的渲染需要构建不同的对象(即相当于创建不同的画笔)。

 public class Shader01 extends View{
    Bitmap qq2 = null;
    int qq2width = 0;
    int qq2height = 0;
    Paint paint = null;
 
    Shader bitmapShaper = null;//Bitmap渲染
    Shader linearGradient = null;//线性渲染
    Shader radialGradient = null;//环形渲染
    Shader sweepGradient = null;//梯度渲染
    Shader composeShaper = null;//混合渲染
 
    ShapeDrawable shapeDrawable = null;
 
    public Shader01(Context context) {
     super(context);
     qq2 = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
  
     qq2width = qq2.getWidth();//得到图片的宽度
     qq2height = qq2.getHeight();//得到图片的高度
  
     //创建BitmapShader对象
     bitmapShaper = new BitmapShader(qq2,Shader.TileMode.REPEAT,Shader.TileMode.MIRROR);
//要想裁剪需要使用BitmapShader类来裁剪,得到图片的宽度和高度
  
     //创建linearGradient对象并设置变化的颜色数组
     linearGradient = new LinearGradient(10, 0, 50, 100, 
        new int []{Color.RED,Color.YELLOW,Color.BLACK}, null, Shader.TileMode.MIRROR);
  
     //混合渲染
     composeShaper =new ComposeShader(linearGradient, bitmapShaper, PorterDuff.Mode.DARKEN);//也可选用其他的混合
  
     //环形渲染
     radialGradient = new RadialGradient(50, 200, 50, 
        new int[]{Color.GREEN,Color.RED,Color.BLUE}, null, Shader.TileMode.REPEAT);
  
     //梯度渲染
     sweepGradient = new SweepGradient(30, 30, new int[]{Color.GREEN,Color.RED,Color.BLUE}, null);
     paint = new Paint();//创建画笔  
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     shapeDrawable = new ShapeDrawable(new OvalShape());//设置绘制椭圆
     shapeDrawable.getPaint().setShader(bitmapShaper);//设置要绘制的椭圆形的图片
     shapeDrawable.setBounds(0,0,qq2width,qq2height);//设置要显示的区域
     shapeDrawable.draw(canvas);//绘制图片
  
     paint.setShader(linearGradient);//绘制线性渲染
     canvas.drawRect(200,0,320,50, paint);
  
     paint.setShader(composeShaper);//绘制混合渲染
     canvas.drawRect(200,55,320,105, paint);
  
     paint.setShader(radialGradient);//绘制环形渲染
     canvas.drawRect(200,200,320,250, paint);
  
     paint.setShader(sweepGradient);//绘制梯度渲染
     canvas.drawRect(200,110,320,160, paint); 
    }

   }

第九部分 双缓冲技术

原理:当一个动画争先显示时,程序又在改变它,前面的还没画完,程序又请求重新绘制,这时就会出现闪屏。为避免这种情况,可以使用双缓冲技术,将要处理好的的图片在内存中处理好之后,再将其显示到屏幕上。Android中SurfaceView类本身就是一个双缓冲机制,所以游戏开发中用SurfaceView用得更多,效率也更高。下例是针对View类实现双缓冲技术的例子。

public class BufferView extends View implements Runnable{-----------
    Bitmap bitmap1= null;
    Bitmap bufferBitmap = null;//创建缓冲区
 
    Canvas canvas1 = null;
    Paint paint = null;

    public BufferView(Context context) {
     super(context);
     bitmap1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
  
     bufferBitmap = Bitmap.createBitmap(320,480,Config.ARGB_8888);//创建屏幕大小的缓冲区
  
     canvas1 = new Canvas();//创建画布(程序中出现了两块画布)
     paint = new Paint();
  
     canvas1.setBitmap(bufferBitmap);//将内容绘制在bufferBitmap缓冲区上,可理解为将缓冲区作为画布。
  
     canvas1.drawBitmap(bitmap1, 0,0, paint);//将图片绘制到缓冲区上
  
     new Thread(this).start();
    }
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);
     canvas.drawBitmap(bufferBitmap, 0,0, paint);//将bufferBitmap缓冲区上画布绘制到屏幕上去
    }
    @Override
    public void run() {
     while(!Thread.currentThread().isInterrupted()){
      try{
       Thread.sleep(200);
      }catch(Exception e){
       Thread.currentThread().interrupt();
      }
      postInvalidate();
     }
    }
   }

第十部分 全屏显示及获取屏幕属性

如果想像G1游戏那样,当我们把手机屏幕横放时,应用程序会自动变为横屏模式。其实可以通过下面两个方法实现这个功能。

法一:双击AndroidManifest.xml文件,选择Application选项卡,选中Activity类,再找到Screen orientation选项 ,选择 senor 最后保存即可。在真机上就能看到效果
法二:在AndroidManifest.xml文件中设计如下中加入android:screenOrientation="senor"即可。如下:


   public class FullScreen extends Activity{
    public TextView textView_FullScreen;//定义一个TextView来显示屏幕属性
    public void onCreate(Bundle savedInstanceState){
     super.onCreate(savedInstanceState);
  
     requestWindowFeature(Window.FEATURE_NO_TITLE);//通过requestWindowFeature方法来设置为无标题栏
     getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
              WindowManager.LayoutParams.FLAG_FULLSCREEN);//通过setFlags方法设置为全屏模式 
     setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);//通过setRequestedOrientation方法来设置为横屏
     setContentView(R.layout.fullscreen);
     
     textView_FullScreen = (TextView)this.findViewById(R.id.textView_FullScreen);//得到TextView对象
     
     DisplayMetrics displayMetrics = new DisplayMetrics();//定义DisplayMetrics对象,DisplayMetrics定义了屏幕的一些属性
  
     getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);//通过getMetrics方法来取得窗口属性
  
     int screenWidth = displayMetrics.widthPixels;//得到窗口宽度
     int screenHeight = displayMetrics.heightPixels;//得到窗口高度
  
     textView_FullScreen.setText("屏幕宽度:"+screenWidth+"\n屏幕高度:"+screenHeight);
    }
   }

第十一部分 Tween动画

第一种方法 在代码中设计

public class AnimationView extends View{
    public Animation animationAlpha = null;
    public Animation animationScale = null;
    public Animation animationTranslate = null;
    public Animation animationRotate = null;
 
    Bitmap bitmap1 = null;

    public AnimationView(Context context) {
     super(context);
     bitmap1 = ((BitmapDrawable)getResources().getDrawable(R.drawable.dog)).getBitmap();//加载资源
    }
    public void onDraw(Canvas canvas){
     canvas.drawBitmap(bitmap1, 50,100, null);
    }
    public boolean onKeyUp(int keyCode,KeyEvent event){
     switch(keyCode){
      /* 
      * Alpha透明度动画效果。其属性设置格式为:
      * AlphaAnimation(float fromAlpha,float toAlpha)
      * fromAlpha---为动画起始时透明度
      * toAlpha---动画结束时透明度(0.0表示完全透明,1.0表示完全不透明)
      * 
      * setDuration(long durationMillis);设置动画显示的时间 单位为毫秒
      * startAnimation(Animation animation);开始播放动画
      */
     case KeyEvent.KEYCODE_DPAD_UP:
      animationAlpha = new AlphaAnimation(0.0f, 1.0f);//创建Alpha动画
      animationAlpha.setDuration(3000);//动画持续时间
      this.startAnimation(animationAlpha);//开始播放动画
      break;
      /* 
      * Scale伸缩动画效果.。其属性设置如下:
      * ScaleAnimation(fromX, toX, fromY, toY, pivotXType, pivotXValue, pivotYType, pivotYValue)
      * fromX,toX 为起始和结束时x坐标上的伸缩尺寸
      * fromY,toY 为起始和结束时y坐标上的伸缩尺寸
      * pivotXType,pivotYType 分别为x,y的伸缩模式
      * pivotXVale,pivotYVale 分别为伸缩动画相对于x,y的坐标开始位置
      */
     case KeyEvent.KEYCODE_DPAD_DOWN:
      animationScale = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF,
            0.5f, Animation.RELATIVE_TO_SELF, 0.5f);//创建Scale动画
      animationScale.setDuration(500);//动画持续的时间
      this.startAnimation(animationScale);//开始播放动画
      /*
      * Translate移动动画效果。其属性设置如下:
      * TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta)
      * fromXDelta ,fromYDelta 分别为起始x,y坐标
      * toXDelta,toYDelta 分别为终点时x,y坐标
      */
     case KeyEvent.KEYCODE_DPAD_LEFT:
      animationTranslate = new TranslateAnimation(10, 100, 10, 100);//创建Translate动画
      animationTranslate.setDuration(1000);//动画持续时间
      this.startAnimation(animationTranslate);//开始播放动画
      break;
      /*
      * Rotate旋转动画效果
      * RotateAnimation(fromDegrees, toDegrees, pivotXType, pivotXValue, pivotYType, pivotYValue)
      * fromDegrees 开始角度
      * toDegrees 结束角度
      * pivotXValue , pivotYValue 伸缩动画相对于x,y的坐标坐标开始位置
      * pivotXType,pivotYType 分别为x,y的伸缩模式
      */
     case KeyEvent.KEYCODE_DPAD_RIGHT:
      animationRotate = new RotateAnimation(0.0f, 360f, Animation.RELATIVE_TO_SELF,
              0.5f, Animation.RELATIVE_TO_SELF, 0.5f);//创建Rotate动画
      animationRotate.setDuration(1000);//动画持续时间
      this.startAnimation(animationRotate);//动画播放
     }
      return true; 
    }
   } 

需在Activity种实例化

第二种方法 xml设计

  aipha.xml
<?xml version="1.0" encoding="utf-8"?>//也可将这四个xml放在一起 为没一个设置一个id
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<alpha
android:fromAlpha="0.1"
android:toAlpha="1.0"
android:duration="2000"
/>
</set>

rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="+360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="1000" />
</set>

scale.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="500" />
</set>

translate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="10"
android:toXDelta="100"
android:fromYDelta="10"
android:toYDelta="100"
android:duration="1000"
/>
</set>

public class GameView extends View{
private Animation mAnimationAlpha = null;//定义Alpha动画
private Animation mAnimationScale = null;//定义Scale动画
private Animation mAnimationTranslate = null;//定义Translate动画
private Animation mAnimationRotate = null;//定义Rotate动画

Bitmap mBitQQ = null;//定义Bitmap对象
Context mContext = null;
public GameView(Context context){
super(context);
mContext = context;

mBitQQ = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
}
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawBitmap(mBitQQ, 0, 0, null);//绘制图片
}
public boolean onKeyUp(int keyCode, KeyEvent event){
switch ( keyCode ){
case KeyEvent.KEYCODE_DPAD_UP:
mAnimationAlpha = AnimationUtils.loadAnimation(mContext,R.layout.alpha);//装载动画布局
this.startAnimation(mAnimationAlpha);//开始播放动画
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
mAnimationScale = AnimationUtils.loadAnimation(mContext,R.layout.scale);//装载动画布局
this.startAnimation(mAnimationScale);//开始播放动画
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
mAnimationTranslate = AnimationUtils.loadAnimation(mContext,R.layout.translate);//装载动画布局
this.startAnimation(mAnimationTranslate);//开始播放动画
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
mAnimationRotate = AnimationUtils.loadAnimation(mContext,R.layout.rotate);//装载动画布局
this.startAnimation(mAnimationRotate);//开始播放动画
break;
}
return true;
}
}

Framed动画

第一种方法 在代码中设计

public class GameView extends View{    
    private AnimationDrawable animationDrawable = null;//定义AnimationDrawable装载动画
    Context      mContext  = null;
    Drawable    mBitAnimation  = null;//定义一个Drawable对象
    public GameView(Context context){
     super(context);
     mContext = context; 
     animationDrawable = new AnimationDrawable();//实例化AnimationDrawable对象 
     
     for (int i = 1; i <= 15; i++){//利用循环装载所有名字类似的资源(图片命名时是有规律的 所以才能用此循环)
      int id = getResources().getIdentifier("a" + i, "drawable", mContext.getPackageName());------------------------需要深入
      mBitAnimation = getResources().getDrawable(id);
   
      animationDrawable.addFrame(mBitAnimation, 500);//通过addFrame方法把每一帧添加进去,每一帧显示的时间为500毫秒
     }
     animationDrawable.setOneShot( false );//利用setOneShot方法设置播放模式是否循环false表示循环而true表示不循环

     this.setBackgroundDrawable(animationDrawable);// 加载本类将要显示这个动画
    } 
    public void onDraw(Canvas canvas){
     super.onDraw(canvas);  
    }
    public boolean onKeyUp(int keyCode, KeyEvent event){
     switch ( keyCode ){
      case KeyEvent.KEYCODE_DPAD_UP:  
      animationDrawable.start();//最后通过start方法播放动画
       break;
     }
     return true;
    }
   } 

要想显示Frame动画,还要在Activity中添加GameView对象

第二种方法:在XML文件中的设计

 aipha.xml
<?xml version="1.0" encoding="utf-8"?>//也可将这四个xml放在一起 为没一个设置一个id
<set xmlns:android="http://schemas.android.com/apk/res/android" >
<alpha
android:fromAlpha="0.1"
android:toAlpha="1.0"
android:duration="2000"
/>
</set>

rotate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="+360"
android:pivotX="50%"
android:pivotY="50%"
android:duration="1000" />
</set>

scale.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.0"
android:fromYScale="0.0"
android:toYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:fillAfter="false"
android:duration="500" />
</set>

translate.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="10"
android:toXDelta="100"
android:fromYDelta="10"
android:toYDelta="100"
android:duration="1000"
/>
</set>

public class GameView extends View{
private Animation mAnimationAlpha = null;//定义Alpha动画
private Animation mAnimationScale = null;//定义Scale动画
private Animation mAnimationTranslate = null;//定义Translate动画
private Animation mAnimationRotate = null;//定义Rotate动画

Bitmap mBitQQ = null;//定义Bitmap对象
Context mContext = null;
public GameView(Context context){
super(context);
mContext = context;

mBitQQ = ((BitmapDrawable) getResources().getDrawable(R.drawable.qq)).getBitmap();//装载资源
}
public void onDraw(Canvas canvas){
super.onDraw(canvas);
canvas.drawBitmap(mBitQQ, 0, 0, null);//绘制图片
}
public boolean onKeyUp(int keyCode, KeyEvent event){
switch ( keyCode ){
case KeyEvent.KEYCODE_DPAD_UP:
mAnimationAlpha = AnimationUtils.loadAnimation(mContext,R.layout.alpha);//装载动画布局
this.startAnimation(mAnimationAlpha);//开始播放动画
break;
case KeyEvent.KEYCODE_DPAD_DOWN:
mAnimationScale = AnimationUtils.loadAnimation(mContext,R.layout.scale);//装载动画布局
this.startAnimation(mAnimationScale);//开始播放动画
break;
case KeyEvent.KEYCODE_DPAD_LEFT:
mAnimationTranslate = AnimationUtils.loadAnimation(mContext,R.layout.translate);//装载动画布局
this.startAnimation(mAnimationTranslate);//开始播放动画
break;
case KeyEvent.KEYCODE_DPAD_RIGHT:
mAnimationRotate = AnimationUtils.loadAnimation(mContext,R.layout.rotate);//装载动画布局
this.startAnimation(mAnimationRotate);//开始播放动画
break;
}
return true;
}
}

还许要在Acitivity类中实例化GameView对象才能显示。

GIF动画播放

其原理:首先需要对GIF动画图像进行解码,然后将GIF中的每一帧分别提取出来保存到一个容器中,然后根据需要绘制每一帧,这样就可以轻松地实现GIF动画的播放了。

下面有个例子,可以在工作中直接使用。

 public class GifDecoder{
    private int     E0;
    private int     E1[];
    private int     E2;
    private int     E6;
    private boolean    E7;
    private int     E8[];
    private int     width;
    private int     height;
    private int     ED;
    private boolean    EE;
    private boolean    EF;
    private int     F0[];
    private int     F1;
    private boolean    F2;
    private int     F3;
    private long    F4;
    private int     F5;
    private static final int F6[] = { 8, 8, 4, 2 };
    private static final int F8[] = { 0, 4, 2, 1 };
    int       curFrame;
    int       poolsize;
    int       FA;
    byte      C2[];
    int       FB;
    int       FC;
    int       FD;
    public GifDecoder(byte abyte0[]){
     E0 = -1;
     E1 = new int[280];
     E2 = -1;
     E6 = 0;
     E7 = false;
     E8 = null;
     width = 0;
     height = 0;
     ED = 0;
     EE = false;
     EF = false;
     F0 = null;
     F1 = 0;
     F5 = 0;
     curFrame = 0;
     C2 = abyte0;
     poolsize = C2.length;
     FA = 0;
    }
    public boolean moreFrames(){
     return poolsize - FA >= 16;
    }
    public void nextFrame(){
     curFrame++;
    }
    public Bitmap decodeImage(){
     return decodeImage(curFrame);
    }
    public Bitmap decodeImage(int i){
     if (i <= E0){
     return null;
     }
     if (E0 < 0){
      if (!E3()){
       return null;
      }
      if (!E4()){
       return null;
      }
     }
     do{
      if (!E9(1)){
       return null;
      }
      int j = E1[0];
      if (j == 59){
       return null;
      }
      if (j == 33){
       if (!E7()){
       return null;
       }
      }
      else if (j == 44){
       if (!E5()){
        return null;
       }
       Bitmap image = createImage();
       E0++;
       if (E0 < i){
        image = null;
       }else{
        return image;
       }
      }
     }
     while (true);
    }
    public void clear(){
     C2 = null;
     E1 = null;
     E8 = null;
     F0 = null;
    }
    private Bitmap createImage(){
     int i = width;
     int j = height;
     int j1 = 0;
     int k1 = 0;
     int ai[] = new int[4096];
     int ai1[] = new int[4096];
     int ai2[] = new int[8192];
     if (!E9(1)){
      return null;
     }
     int k = E1[0];
     int[] image = new int[width * height];
     int ai3[] = E8;
     if (EE){
      ai3 = F0;
     }
     if (E2 >= 0){
      ai3[E2] = 0xffffff;
     }
     int l2 = 1 << k;
     int j3 = l2 + 1;
     int k2 = k + 1;
     int l3 = l2 + 2;
     int k3 = -1;
     int j4 = -1;
     for (int l1 = 0; l1 < l2; l1++){
      ai1[l1] = l1;
     }
     int j2 = 0;
     E2();
     j1 = 0;
     label0: for (int i2 = 0; i2 < j; i2++){
      int i1 = 0;
      do{
       if (i1 >= i){
        break;
       }
       if (j2 == 0){
        int i4 = E1(k2);
        if (i4 < 0){
         return Bitmap.createBitmap(image, width, height, Config.RGB_565);
        }
        if (i4 > l3 || i4 == j3){
         return Bitmap.createBitmap(image, width, height, Config.RGB_565);
        }
        if (i4 == l2){
         k2 = k + 1;
         l3 = l2 + 2;
         k3 = -1;
         continue;
        }
        if (k3 == -1){
         ai2[j2++] = ai1[i4];
         k3 = i4;
         j4 = i4;
         continue;
        }
        int i3 = i4;
        if (i4 == l3){
         ai2[j2++] = j4;
         i4 = k3;
        }
        for (; i4 > l2; i4 = ai[i4]){
         ai2[j2++] = ai1[i4];
        }
        j4 = ai1[i4];
        if (l3 >= 4096){
         return Bitmap.createBitmap(image, width, height, Config.RGB_565);
        }
        ai2[j2++] = j4;
        ai[l3] = k3;
        ai1[l3] = j4;
        if (++l3 >= 1 << k2 && l3 < 4096){
         k2++;
        }
        k3 = i3;
       }
       int l = ai2[--j2];
       if (l < 0){
        return Bitmap.createBitmap(image, width, height, Config.RGB_565);
       }
       if (i1 == 0){
        FC = 0;
        FB = ai3[l];
        FD = 0;
       }else if (FB != ai3[l]){
        for (int mm = FD; mm <= FD + FC; mm++){
         image[j1 * width + mm] = FB;
         }
        FC = 0;
        FB = ai3[l];
        FD = i1;
        if (i1 == i - 1){
         image[j1 * width + i1] = ai3[l];
        }
       }else{
        FC++;
        if (i1 == i - 1){
         for (int mm = FD; mm <= FD + FC; mm++){
          image[j1 * width + mm] = FB;
         }
        }
       }
        i1++;
      }
      while (true);
       if (EF){
        j1 += F6[k1];
        do{
         if (j1 < j){
          continue label0;
         }
         if (++k1 > 3){
          return Bitmap.createBitmap(image, width, height, Config.RGB_565);
         }
         j1 = F8[k1];
        }
        while (true);
       }
       j1++;
     }
      return Bitmap.createBitmap(image, width, height, Config.RGB_565);
    }
    private int E1(int i){
     while (F5 < i){
      if (F2){
       return -1;
      }
      if (F1 == 0){
       F1 = E8();
       F3 = 0;
       if (F1 <= 0){
        F2 = true;
        break;
       }
      }
      F4 += E1[F3] << F5;
      F3++;
      F5 += 8;
      F1--;
     }
     int j = (int) F4 & (1 << i) - 1;
     F4 >>= i;
     F5 -= i;
     return j;
    }
    private void E2(){
     F5 = 0;
     F1 = 0;
     F4 = 0L;
     F2 = false;
     F3 = -1;
    }
    private boolean E3(){
     if (!E9(6)){
      return false;
     }
     return E1[0] == 71 && E1[1] == 73 && E1[2] == 70 && E1[3] == 56 && (E1[4] == 55 || E1[4] == 57) && E1[5] == 97;
    }
    private boolean E4(){
     if (!E9(7)){
      return false;
     }
     int i = E1[4];
     E6 = 2 << (i & 7);
     E7 = EB(i, 128);
     E8 = null;
     return !E7 || E6(E6, true);
    }
    private boolean E5(){
     if (!E9(9)){
      return false;
     }
     width = EA(E1[4], E1[5]);
     height = EA(E1[6], E1[7]);
     int i = E1[8];
     EE = EB(i, 128);
     ED = 2 << (i & 7);
     EF = EB(i, 64);
     F0 = null;
     return !EE || E6(ED, false);
    }
    private boolean E6(int i, boolean flag){
     int ai[] = new int[i];
     for (int j = 0; j < i; j++){
      if (!E9(3)){
       return false;
      }
      ai[j] = E1[0] << 16 | E1[1] << 8 | E1[2] | 0xff000000;
     }
     if (flag){
      E8 = ai;
     }else{
      F0 = ai;
     }
     return true;
    }
    private boolean E7(){
     if (!E9(1)){
      return false;
     }
     int i = E1[0];
     int j = -1;
     switch (i){
      case 249:
       j = E8();
       if (j < 0){
        return true;
       }
       if ((E1[0] & 1) != 0){
        E2 = E1[3];
       }else{
        E2 = -1;
       }
      break;
     }
     do{
      j = E8();
     }
     while (j > 0);
     return true;
    }
    private int E8(){
     if (!E9(1)){
      return -1;
     }
     int i = E1[0];
     if (i != 0 && !E9(i)){
      return -1;
     }else{
      return i;
     }
    }
    private boolean E9(int i){
     if (FA + i >= poolsize){
      return false;
     }
     for (int j = 0; j < i; j++){
      int k = C2[FA + j];
      if (k < 0){
       k += 256;
      }
      E1[j] = k;
     }
     FA += i;
     return true;
    }
    private static final int EA(int i, int j){
     return j << 8 | i;
    }
    private static final boolean EB(int i, int j){
     return (i & j) == j;
    }
   }

    public class GifFrame{ 
     /* 保存gif中所有帧的向量 */
     private Vector frames;   
     /* 当前播放的帧的索引 */
     private int index;
     public GifFrame(){
      frames = new Vector(1);
      index = 0;
     }  
     /* 添加一帧 */
     public void addImage(Bitmap image) {
      frames.addElement(image);
     }
     /* 返回帧数 */
     public int size() {
      return frames.size();
     }
     /* 得到当前帧的图片 */
     public Bitmap getImage() {
      if (size() == 0) {
       return null;
      } else{
       return (Bitmap) frames.elementAt(index);
      }
     }
     /* 下一帧 */
     public void nextFrame(){
      if (index + 1 < size()){
       index++;
      }else{
       index = 0;
      }
     } 
     /* 创建GifFrame */
     public static GifFrame CreateGifImage(byte abyte0[]){
      try{
       GifFrame GF = new GifFrame();
       Bitmap image = null;
       GifDecoder gifdecoder = new GifDecoder(abyte0);
       for (; gifdecoder.moreFrames(); gifdecoder.nextFrame()){
        try{
          image = gifdecoder.decodeImage();
          if (GF != null && image != null){
           GF.addImage(image);
          }
          continue;
         }catch(Exception e){
          e.printStackTrace();
         }
         break;
        }
       gifdecoder.clear();
       gifdecoder = null;
       return GF;
      }catch (Exception e){
       e.printStackTrace();
       return null;
      }
     } 
    }

    public class GameView extends View implements Runnable{
     Context  mContext = null;
     /* 声明GifFrame对象 */
     GifFrame mGifFrame = null;
     public GameView(Context context){
      super(context);
      mContext = context;
      /* 解析GIF动画 */
      mGifFrame=GifFrame.CreateGifImage(fileConnect(this.getResources().openRawResource(R.drawable.gif1)));
      /* 开启线程 */
      new Thread(this).start();
     }
     public void onDraw(Canvas canvas){
      super.onDraw(canvas);
      /* 下一帧 */
      mGifFrame.nextFrame();
      /* 得到当前帧的图片 */
      Bitmap b=mGifFrame.getImage(); 
      /* 绘制当前帧的图片 */
      if(b!=null)
       canvas.drawBitmap(b,10,10,null);
     }
     /**
      * 线程处理
     */
     public void run(){
      while (!Thread.currentThread().isInterrupted()){
       try{
        Thread.sleep(100);
       }catch (InterruptedException e){
        Thread.currentThread().interrupt();
       }
       //使用postInvalidate可以直接在线程中更新界面
        postInvalidate();
      }
     } 
     /* 读取文件 */
     public byte[] fileConnect(InputStream is){
      try{         
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       int ch = 0;
       while( (ch = is.read()) != -1) {
        baos.write(ch);
       }         
       byte[] datas = baos.toByteArray();
       baos.close(); 
       baos = null;
       is.close();
       is = null;
       return datas;
      }catch(Exception e){
       return null;
      }
     }
    }

    public class Activity01 extends Activity{
     private GameView mGameView = null;
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState){
      super.onCreate(savedInstanceState);
      mGameView = new GameView(this);
      setContentView(mGameView);
     }
    }

 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
 
分享到
 
 


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...