一、基础知识:
SurfaceView继承自View,View负责在主线程中更新动画,而SurfaceView是在一个新线程中更新动画。
SurfaceView类的主要方法:
// 在SurfaceView创建时调用
pubilic abstract void surfaceCreated(SurfaceHolder holder)
// 在SurfaceView改变时调用
pubilic abstract void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
// 在SurfaceView销毁时调用
pubilic abstract void surfaceDestroyed(SurfaceHolder holder)
// 绘制SurfaceView画面
protected void onDraw(Canvas canvas)
(参数canvas是该SurfaceView的画笔,每一次SurfaceView中画面改变都是调用了该方法)
二、实现效果:
首先有一副图片从屏幕的左下角开始向右上方运动,当图片上沿与手机屏幕上沿相撞时,图片的水平速度大小与方向均不变,竖直方向上速度大小不变,
方向相反;当下沿相撞后,同样效果,直到图片飞出屏幕。之后,屏幕渐渐地显示一幅图片。
三、编程实现:
1. 界面编辑(res\layout\main.xml):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout>
2. 代码编辑:
(\src\wyf\zcl\MyActivity.java)
package wyf.zcl; /* * 该例子演示surfaceView中简单场景的绘制 * MyActivity.java 为程序的主Activity * MySurfaceView.java 为程序的SurfaceView类 * Constant.java 常量类,将常量全部写在该类中 * OnDrawThread.java 该类的作用是时时刷新onDraw,进行画面的重绘 * PicRunThread.java 该类是控制duke图片运动的类 * */ import android.app.Activity; //引入相关包 import android.content.pm.ActivityInfo; //引入相关包 import android.os.Bundle; //引入相关包 import android.view.Window; //引入相关包 import android.view.WindowManager; //引入相关包 public class MyActivity extends Activity { /** Called when the activity is first created. */ private MySurfaceView msv; //得到surfaceView的引用 @Override public void onCreate(Bundle savedInstanceState) { //Activity的生命周期函数,该函数是在程序创建时调用 super.onCreate(savedInstanceState); msv=new MySurfaceView(MyActivity.this); //实例化MySurfaceView的对象 requestWindowFeature(Window.FEATURE_NO_TITLE); //设置屏幕显示没有title栏 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN , WindowManager.LayoutParams.FLAG_FULLSCREEN); //设置全屏 //设置只允许横屏 this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); setContentView(msv); //设置Activity显示的内容为msv } }
package wyf.zcl; import android.view.Display; //Constant.java 常量类,将常量全部写在该类中 public class Constant { public static int SCREENWIDTH=480; //屏幕宽(本程序为横屏) public static int SCREENHEIGHT=320; //屏幕高 public static int PICWIDTH=64; //图片宽度 public static int PICHEIGHT=64; //图片高度 public static int ONDRAWSPEED=30; //onDraw线程类的绘制间隔时间 public static float PICXSPEED=1.5f; //图片水平移动速度 public static float PICYSPEED=2; //图片垂直移动速度 public static int PICRUNSPEED=30; //图片的运动线程的刷新速度 public static int PICALPHASPEED=20; //图片渐暗效果演示刷新速度 }
package wyf.zcl; 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.Display; //引入相关包 import android.view.SurfaceHolder; //引入相关包 import android.view.SurfaceView; //引入相关包 public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{ //此处实现SurfaceHolder.Callback接口,为surfaceView添加生命周期回调函数 int dy=Display.DEFAULT_DISPLAY; MyActivity ma; //得到MyActivity的引用 Paint paint; //画笔的引用 OnDrawThread odt; //OnDrawThread类引用 PicRunThread prt; //图片运动的Thread类引用 private float picX=0; //图片x坐标 private float picY=0; //图片y坐标 boolean picAlphaFlag=false; //图片变暗效果的标记,false为不显示,true为显示。 int picAlphaNum=0; //图片变暗效果中画笔的alpha值 public MySurfaceView(Context context) { super(context); this.ma=(MyActivity) context; //将ma的引用指向调用了该Surfaceview类构造器方法的对象,本例为MyActivity this.getHolder().addCallback(this); //注册回调接口 paint=new Paint(); //实例化画笔 odt=new OnDrawThread(this); //实例化OnDrawThread类 prt=new PicRunThread(this); //实例化PicRunThread类 prt.start(); } public void setPicX(float picX) { //图片x坐标的设置器 this.picX = picX; } public void setPicY(float picY) { //图片y坐标的设置器 this.picY = picY; } public void setPicAlphaNum(int picAlphaNum) {//图片变暗效果alpha参数设置器 this.picAlphaNum = picAlphaNum; } @Override protected void onDraw(Canvas canvas) { //onDraw方法,此方法用于绘制图像,图形等 super.onDraw(canvas); paint.setColor(Color.WHITE); //设置画笔为白色 canvas.drawRect(0, 0, Constant.SCREENWIDTH, Constant.SCREENHEIGHT, paint); //此处画了一个白色的全屏幕的矩形,目的是设置背景为白色,同时每次重绘时清除背景 //进行平面贴图 Bitmap bitmapDuke=BitmapFactory.decodeResource(ma.getResources(), R.drawable.duke); canvas.drawBitmap(bitmapDuke, picX, picY, paint); //图片渐暗效果 if(picAlphaFlag){ Bitmap bitmapBG=BitmapFactory.decodeResource(ma.getResources(), R.drawable.jpg1); paint.setAlpha(picAlphaNum); canvas.drawBitmap(bitmapBG, 0,0, paint); } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { //此方法为当surfaceView改变时调用,如屏幕大小改变。 } @Override public void surfaceCreated(SurfaceHolder holder) {//此方法为在surfaceView创建时调用 odt.start(); //启动onDraw的绘制线程 } @Override public void surfaceDestroyed(SurfaceHolder holder) {//此方法为在surfaceView销毁前调用 } }
package wyf.zcl; import android.graphics.Canvas; //引入相关包 import android.view.SurfaceHolder; //引入相关包 //该类的作用是时时刷新onDraw,进行画面的重绘 public class OnDrawThread extends Thread{ MySurfaceView msv; //得到MySurfaceView的引用 SurfaceHolder sh; //SurfaceHolder引用 public OnDrawThread(MySurfaceView msv) { super(); this.msv = msv; //构造方法中,将msv引用指向调用了该类的MySurfaceView的对象 sh=msv.getHolder(); } @Override public void run() { super.run(); Canvas canvas = null; //Canvas的引用 while(true){ try{ canvas=sh.lockCanvas(null); //将canvas的引用指向surfaceView的canvas的对象 synchronized(this.sh){ //绘制过程,可能带来同步方面的问题,加锁 if(canvas!=null){ msv.onDraw(canvas); } } }finally{ try{ if(sh!=null){ sh.unlockCanvasAndPost(canvas); //绘制完后解锁 } }catch(Exception e){e.printStackTrace();} } try{ Thread.sleep(Constant.ONDRAWSPEED); //休息1秒钟 }catch(Exception e){e.printStackTrace();} } } }
package wyf.zcl; //该类是控制duke图片运动的类 public class PicRunThread extends Thread{ MySurfaceView msv; //MySurfaceView的引用 private float picX=0; //图片x坐标 private float picY=Constant.SCREENHEIGHT-Constant.PICHEIGHT; //图片y坐标 boolean yRunFlag=false; //y方向上的运动标记,false时y=y+speed,true时y=y-speed int picAlphaNum=0; //图片变暗效果中画笔的alpha值 public PicRunThread(MySurfaceView msv) { super(); this.msv = msv; //将该线程类的引用指向调用其的MySurfaceView的对象 } @Override public void run() { super.run(); while(true){ //控制duke图片的运动 while(this.picX<Constant.SCREENWIDTH){ //当图片的左边完全超过屏幕的右边时,循环结束 msv.setPicX(picX); msv.setPicY(picY); picX=picX+Constant.PICXSPEED; if(yRunFlag){//应该向上运动,自减 picY=picY-Constant.PICYSPEED; }else{//应该向下运动,自加 picY=picY+Constant.PICYSPEED; } if(picY<=0){ //到达屏幕上沿 yRunFlag=false; }else if(picY>Constant.SCREENHEIGHT-Constant.PICHEIGHT){ //到达屏幕下沿 yRunFlag=true; } try{ Thread.sleep(Constant.PICRUNSPEED); }catch(Exception e){e.printStackTrace();} } //图片变暗效果演示 msv.picAlphaFlag=true; //开启图片变暗效果 for(picAlphaNum=0;picAlphaNum<=255;picAlphaNum++){ if(picAlphaNum==255){ msv.picAlphaFlag=false; //当图片变暗效果结束,标记重置 picX=0; //图片x坐标 picY=Constant.SCREENHEIGHT-Constant.PICHEIGHT; //图片y坐标 System.out.println(msv.picAlphaFlag+"picX:"+picX+"picY:"+picY); } msv.setPicAlphaNum(picAlphaNum); try{ Thread.sleep(Constant.PICALPHASPEED); }catch(Exception e){e.printStackTrace();} } } } }
代码中涉及一些java的基础知识,我做了一点笔记,如下:
[ extends ]:
一个类使用关键字extends继承其他类,关键字extends出现在类声明时的类名后,
extends后面跟着的是要继承的类的名称,extends实现了继承。在Java中的类只能继承一个类。
[ super ]:
B 继承 A ,B想调用A的方法,那么就可以 用super.A的方法。如果用中文解释:super就是父类的一个别名。
[ implements ]:
implements是一个类实现一个接口用的关键字,
[ extends和implements区别]:
extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承, JAVA中不支持多重继承,但是可以用接口来实现,这样就要用到implements,继承只能继承一个类, 但implements可以实现多个接口,用逗号分开就行了 比如 class A extends B implements C,D,E