Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 高級開發 >> Android 自定義控件(SurfaceView與view結合)

Android 自定義控件(SurfaceView與view結合)

編輯:高級開發

作者:Legend

  QQ:158067568

  上一節小試牛刀,介紹了一個簡單的SurfaceVIEw的例子,如果用於實際開發,那還差得遠呢。本節介紹SurfaceView與VIEw結合使用的例子,SurfaceVIEw部分與球類稍作改動,這裡就不在贅述。主要介紹一下如何在View中成功的把SurfaceView添加進來,並且通過widget中默認的控件來操作自定義的SurfaceVIEw。

  View中添加SurfaceVIEw

  還記得我上一節中的SurfaceView類BallSurfaceVIEw的構造方法麼?BallSurfaceView(Context context)沒錯就是這個,但是如果我們要在vIEw中添加,還是用這個構造方法就會報錯。感謝mars老師的android群,裡面的大蝦們幫我解決了這個問題

  其實只要使用如下構造方法,然後注意幾點就ok了。

  Java代碼

  1. public BallSurfaceVIEw(Context context, AttributeSet attrs) {

  2. super(context,attrs);

  3. …..

  public BallSurfaceVIEw(Context context, AttributeSet attrs) {

  super(context,attrs);

  …..

  就是上面的構造方法,是符合vIEw的。AttributeSet是提供一些設置的類,可以參考API。

  但是值得注意的是,不要再SurfaceView中去綁定VIEw,這樣會帶來意想不到的錯誤。

  實現

  我將把代碼全部貼出,供大家參考。

  Java代碼

  1. package cn.edu.heut.zcl;

  2.

  3. import android.content.Context;

  4. import android.graphics.Canvas;

  5. import android.graphics.Color;

  6. import android.graphics.Paint;

  7. import android.util.AttributeSet;

  8. import android.util.DisplayMetrics;

  9. import android.vIEw.SurfaceHolder;

  10. import android.view.SurfaceVIEw;

  11.

  12. public class BallSurfaceView extends SurfaceVIEw

  13. implements SurfaceHolder.Callback{

  14. // SportActivity sportActivity ;//調用該SurfaceVIEw的上下文引用

  15. private Ball ball ;//小球

  16. public static final int initX = 100;

  17. public static final int initY = 100;

  接上頁

  18. SurfaceHolder holder ;

  19. public int screenWidth ;

  20. public int screenHeight ;

  21. public BallSurfaceVIEw(Context context, AttributeSet attrs) {

  22. super(context,attrs);

  23. ball = new Ball(initX, initY, this);

  24. holder = this.getHolder();

  25. holder.addCallback(this);

  26. //獲得屏幕尺寸

  27. DisplayMetrics dm = new DisplayMetrics();

  28. dm = context.getApplicationContext().getResources().getDisplayMetrics();

  29. screenWidth = dm.widthPixels;

  30. screenHeight = dm.heightPixels;

  31. }

  32.

  33. @Override

  34. protected void onDraw(Canvas canvas) {

  35. super.onDraw(canvas);

  36.

  37. if(canvas == null) canvas = holder.lockCanvas();//鎖定畫布

  38. Paint p = new Paint();

  39. int c = p.getColor();

  40. p.setColor(Color.WHITE);//設置背景白色

  41. if(canvas != null)

  42. canvas.drawRect(0, 0, screenWidth, screenHeight, p);

  43. p.setColor(c);

  44. ball.onDraw(canvas);

  45. holder.unlockCanvasAndPost(canvas);//釋放鎖

  46. }

  47.

  48. @Override

  49. public void surfaceChanged(SurfaceHolder holder, int format, int width,

  50. int height) {

  51.

  52. }

  53.

  54. @Override

  55. public void surfaceCreated(SurfaceHolder holder) {

  56. new RefreshThread().start();

  57. }

  58.

  59. @Override

  60. public void surfaceDestroyed(SurfaceHolder holder) {

  61.

  62. }

  63.

  64. public void setStop(){

  65. ball.setStop(true);

  66. }

  67. public void setStart(){

  68. ball.setStop(false);

  69. }

  70. public void setRestart(){

  接上頁

  71. ball.setPosition(initX, initY);

  72. ball.setMaxHeight(initY);

  73. }

  74. private class RefreshThread extends Thread{

  75.

  76. @Override

  77. public void run() {

  78.

  79. while(true){

  80. Canvas canvas = null;

  81. try{

  82. onDraw(canvas);

  83. }catch(Exception e){

  84. e.printStackTrace();

  85. }

  86.

  87. try {

  88. Thread.sleep(40);

  89. } catch (InterruptedException e) {

  90. e.printStackTrace();

  91. }

  92. }

  93. }

  94.

  95. }

  96.

  97. }

  98.

  99.

  100. package cn.edu.heut.zcl;

  101.

  102. import android.graphics.Bitmap;

  103. import android.graphics.BitmapFactory;

  104. import android.graphics.Canvas;

  105. import android.graphics.Color;

  106. import android.graphics.Paint;

  107. import android.util.DisplayMetrics;

  108.

  109. /**

  110. * 球類

  111. * @author zcl

  112. *

  113. */

  114. public class Ball {

  115.

  116. /**

  117. * 球的高

  118. */

  119. public static final int HEIGHT = 93;

  120. /**

  121. * 球的寬

  122. */

  123. public static final int WIDTH = 93;

  124.

  125. private static final int STEPLENGTH = 10;//每次運動的間距

  126. private static final float REDUCEPERCENTAGE = 0.35F;//遞減系數

  127. private int stepReduce ;//每次反向運動的縮短的距離

  128.

  129. private boolean stop = false;

  130.

  131. public void setStop(boolean stop) {

  132. this.stop = stop;

  133. }

  接上頁

  134. private float runX ;//球的位置

  135. private float runY ;//球的位置

  136. private BallSurfaceVIEw bsv ;

  137. private boolean upDirection = false;//if true,up direction,or is down direction

  138. private float maxHeight ;//當前運動最高的高度

  139. private Paint paint ;

  140.

  141. Bitmap ballBitmap ;//球的圖片

  142. public Ball(float initX , float initY , BallSurfaceVIEw bsv){

  143. this.runX = initX;

  144. this.runY = initY ;

  145. maxHeight = initY;

  146. this.bsv = bsv;

  147. ballBitmap = BitmapFactory.decodeResource(bsv.getResources(), R.drawable.ball);//加載圖片

  148. paint = new Paint();

  149. }

  150.

  151. public void onDraw(Canvas canvas) {

  152. int c = paint.getColor();//保存顏色,之後還原為之前顏色

  153. if( !stop ) boundaryTest();

  154. if(canvas != null) canvas.drawBitmap(ballBitmap,runX,runY,paint);

  155. paint.setColor(c);

  156. if( !stop ) move();

  157. }

  158. /**

  159. * 運動

  160. */

  161. private void move() {

  162. if(maxHeight >= (bsv.screenHeight - HEIGHT)) {

  163. return;

  164. }

  165. if(upDirection){//向上

  166. runY = runY + STEPLENGTH ;

  167. }else{

  168. runY = runY - STEPLENGTH ;

  169. }

  170. }

  171.

  172. /**

  173. * 邊界檢測,使球不會飛出邊界

  174. */

  175. private void boundaryTest(){

  176.

  177. if(runY > bsv.screenHeight - HEIGHT){//向下運動到頭

  178. upDirection = !upDirection;//方向置反

  179. runY = bsv.screenHeight - HEIGHT;

  180. stepReduce = (int) (maxHeight * REDUCEPERCENTAGE);

  181. maxHeight = maxHeight + stepReduce ;//最大高度遞減

  接上頁

  182.

  183. }

  184. if(runY < maxHeight ){//向上運動到頭

  185. upDirection = !upDirection;//方向置反

  186. if(maxHeight >= (bsv.screenHeight - HEIGHT)) return;

  187. runY = maxHeight ;

  188.

  189. }

  190. }

  191. public void setPosition(float x,float y){

  192. this.runX = x;

  193. this.runY = y;

  194. }

  195. public void setMaxHeight(float y){

  196. this.maxHeight = y;

  197. }

  198. }

  199.

  200.

  201. package cn.edu.heut.zcl;

  202.

  203. import android.app.Activity;

  204. import android.content.pm.ActivityInfo;

  205. import android.os.Bundle;

  206. import android.util.DisplayMetrics;

  207. import android.view.VIEw;

  208. import android.vIEw.Window;

  209. import android.vIEw.WindowManager;

  210. import android.widget.Button;

  211.

  212. public class SportActivity extends Activity {

  213.

  214. Button butStop;

  215. Button butStart;

  216. Button butRestart;

  217.

  218. BallSurfaceVIEw bsv ;

  219. /** Called when the activity is first created. */

  220. @Override

  221. public void onCreate(Bundle savedInstanceState) {

  222. super.onCreate(savedInstanceState);

  223. // bsv = new BallSurfaceVIEw(this);

  224. //下兩句為設置全屏

  225. requestWindowFeature(Window.FEATURE_NO_TITLE);

  226. getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ,

  227. WindowManager.LayoutParams.FLAG_FULLSCREEN);

  228.

  229. setContentVIEw(R.layout.main);

  230. butStop =(Button)findVIEwById(R.id.butStop);

  231. butStop.setOnClickListener(new listener());

  接上頁

  232. butStart =(Button)findVIEwById(R.id.butStart);

  233. butStart.setOnClickListener(new listener());

  234. butRestart =(Button)findVIEwById(R.id.butRestart);

  235. butRestart.setOnClickListener(new listener());

  236. bsv = (BallSurfaceView) findViewById(R.id.ballSurfaceVIEw);

  237. }

  238. class listener implements VIEw.OnClickListener{

  239.

  240. @Override

  241. public void onClick(VIEw v) {

  242. Button but = (Button)v;

  243. switch(but.getId()){

  244. case R.id.butStop:

  245. bsv.setStop();

  246. break;

  247. case R.id.butStart:

  248. bsv.setStart();

  249. break;

  250. case R.id.butRestart:

  251. bsv.setRestart();

  252. break;

  253. }

  254.

  255. }

  256.

  257. }

  258.

  259. }

  260.

  261.

  262. < ?XML version="1.0" encoding="utf-8"?>

  263. < LinearLayout XMLns:android="http://schemas.android.com/apk/res/android"

  264. android:orIEntation="vertical"

  265. android:layout_width="fill_parent"

  266. android:layout_height="fill_parent"

  267. >

  268. < LinearLayout

  269. android:orIEntation="horizontal"

  270. android:layout_width="fill_parent"

  271. android:layout_height="wrap_content"

  272. >

  273. < Button android:id="@+id/butStop"

  274. android:text="stop"

  275. android:layout_height="wrap_content"

  276. android:layout_width="wrap_content"

  277. >

  278. < /Button>

  279. < Button android:id="@+id/butStart"

  280. android:text="Start"

  281. android:layout_height="wrap_content"

  282. android:layout_width="wrap_content"

  接上頁

  283. >

  284. < /Button>

  285. < Button android:id="@+id/butRestart"

  286. android:text="ReStart"

  287. android:layout_height="wrap_content"

  288. android:layout_width="wrap_content"

  289. >

  290. < /Button>

  291. < /LinearLayout>

  292. < FrameLayout

  293. android:layout_width="fill_parent"

  294. android:layout_height="wrap_content">

  295. < cn.edu.heut.zcl.BallSurfaceVIEw

  296. android:id="@+id/ballSurfaceVIEw"

  297. android:layout_width="fill_parent"

  298. android:layout_height="fill_parent">

  299. < /cn.edu.heut.zcl.BallSurfaceVIEw>

  300. < /FrameLayout>

  301. < /LinearLayout>

  package cn.edu.heut.zcl;

  import android.content.Context;

  import android.graphics.Canvas;

  import android.graphics.Color;

  import android.graphics.Paint;

  import android.util.AttributeSet;

  import android.util.DisplayMetrics;

  import android.vIEw.SurfaceHolder;

  import android.view.SurfaceVIEw;

  public class BallSurfaceView extends SurfaceVIEw

  implements SurfaceHolder.Callback{

  // SportActivity sportActivity ;//調用該SurfaceVIEw的上下文引用

  private Ball ball ;//小球

  public static final int initX = 100;

  public static final int initY = 100;

  SurfaceHolder holder ;

  public int screenWidth ;

  public int screenHeight ;

  public BallSurfaceVIEw(Context context, AttributeSet attrs) {

  super(context,attrs);

  ball = new Ball(initX, initY, this);

  holder = this.getHolder();

  holder.addCallback(this);

  //獲得屏幕尺寸

  DisplayMetrics dm = new DisplayMetrics();

  dm =

  接上頁

context.getApplicationContext().getResources().getDisplayMetrics();

  screenWidth = dm.widthPixels;

  screenHeight = dm.heightPixels;

  }

  @Override

  protected void onDraw(Canvas canvas) {

  super.onDraw(canvas);

  if(canvas == null) canvas = holder.lockCanvas();//鎖定畫布

  Paint p = new Paint();

  int c = p.getColor();

  p.setColor(Color.WHITE);//設置背景白色

  if(canvas != null)

  canvas.drawRect(0, 0, screenWidth, screenHeight, p);

  p.setColor(c);

  ball.onDraw(canvas);

  holder.unlockCanvasAndPost(canvas);//釋放鎖

  }

  @Override

  public void surfaceChanged(SurfaceHolder holder, int format, int width,

  int height) {

  }

  @Override

  public void surfaceCreated(SurfaceHolder holder) {

  new RefreshThread().start();

  }

  @Override

  public void surfaceDestroyed(SurfaceHolder holder) {

  }

  public void setStop(){

  ball.setStop(true);

  }

  public void setStart(){

  ball.setStop(false);

  }

  public void setRestart(){

  ball.setPosition(initX, initY);

  ball.setMaxHeight(initY);

  }

  private class RefreshThread extends Thread{

  @Override

  public void run() {

  while(true){

  Canvas canvas = null;

  try{

  onDraw(canvas);

  }catch(Exception e){

  e.printStackTrace();

  }

  try {

  Thread.sleep(40);

  } catch (InterruptedException e) {

  e.printStackTrace();

  }

  }

  }

  }

  }

  package cn.edu.heut.zcl;

  import android.graphics.Bitmap;

  import android.graphics.BitmapFactory;

  接上頁

  import android.graphics.Canvas;

  import android.graphics.Color;

  import android.graphics.Paint;

  import android.util.DisplayMetrics;

  /**

  * 球類

  * @author zcl

  *

  */

  public class Ball {

  /**

  * 球的高

  */

  public static final int HEIGHT = 93;

  /**

  * 球的寬

  */

  public static final int WIDTH = 93;

  private static final int STEPLENGTH = 10;//每次運動的間距

  private static final float REDUCEPERCENTAGE = 0.35F;//遞減系數

  private int stepReduce ;//每次反向運動的縮短的距離

  private boolean stop = false;

  public void setStop(boolean stop) {

  this.stop = stop;

  }

  private float runX ;//球的位置

  private float runY ;//球的位置

  private BallSurfaceVIEw bsv ;

  private boolean upDirection = false;//if true,up direction,or is down direction

  private float maxHeight ;//當前運動最高的高度

  private Paint paint ;

  Bitmap ballBitmap ;//球的圖片

  public Ball(float initX , float initY , BallSurfaceVIEw bsv){

  this.runX = initX;

  this.runY = initY ;

  maxHeight = initY;

  this.bsv = bsv;

  ballBitmap = BitmapFactory.decodeResource(bsv.getResources(), R.drawable.ball);//加載圖片

  paint = new Paint();

  }

  public void onDraw(Canvas canvas) {

  int c = paint.getColor();//保存顏色,之後還原為之前顏色

  if( !stop ) boundaryTest();

  if(canvas != null) canvas.drawBitmap(ballBitmap,runX,runY,paint);

  paint.setColor(c);

  if( !stop ) move();

  }

  /**

  * 運動

  */

  private void move() {

  if(maxHeight >= (bsv.screenHeight - HEIGHT)) {

  接上頁

  return;

  }

  if(upDirection){//向上

  runY = runY + STEPLENGTH ;

  }else{

  runY = runY - STEPLENGTH ;

  }

  }

  /**

  * 邊界檢測,使球不會飛出邊界

  */

  private void boundaryTest(){

  if(runY > bsv.screenHeight - HEIGHT){//向下運動到頭

  upDirection = !upDirection;//方向置反

  runY = bsv.screenHeight - HEIGHT;

  stepReduce = (int) (maxHeight * REDUCEPERCENTAGE);

  maxHeight = maxHeight + stepReduce ;//最大高度遞減

  }

  if(runY < maxHeight ){//向上運動到頭

  upDirection = !upDirection;//方向置反

  if(maxHeight >= (bsv.screenHeight - HEIGHT)) return;

  runY = maxHeight ;

  }

  }

  public void setPosition(float x,float y){

  this.runX = x;

  this.runY = y;

  }

  public void setMaxHeight(float y){

  this.maxHeight = y;

  }

  }

  package cn.edu.heut.zcl;

  import android.app.Activity;

  import android.content.pm.ActivityInfo;

  import android.os.Bundle;

  import android.util.DisplayMetrics;

  import android.view.VIEw;

  import android.vIEw.Window;

  import android.vIEw.WindowManager;

  import android.widget.Button;

  public class SportActivity extends Activity {

  Button butStop;

  Button butStart;

  Button butRestart;

  BallSurfaceVIEw bsv ;

  /** Called when the activity is first created. */

  @Override

  public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);

  // bsv = new BallSurfaceVIEw(this);

  //下兩句為設置全屏

  requestWindowFeature(Window.FEATURE_NO_TITLE);

  getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN ,

  接上頁

  WindowManager.LayoutParams.FLAG_FULLSCREEN);

  setContentVIEw(R.layout.main);

  butStop =(Button)findVIEwById(R.id.butStop);

  butStop.setOnClickListener(new listener());

  butStart =(Button)findVIEwById(R.id.butStart);

  butStart.setOnClickListener(new listener());

  butRestart =(Button)findVIEwById(R.id.butRestart);

  butRestart.setOnClickListener(new listener());

  bsv = (BallSurfaceView) findViewById(R.id.ballSurfaceVIEw);

  }

  class listener implements VIEw.OnClickListener{

  @Override

  public void onClick(VIEw v) {

  Button but = (Button)v;

  switch(but.getId()){

  case R.id.butStop:

  bsv.setStop();

  break;

  case R.id.butStart:

  bsv.setStart();

  break;

  case R.id.butRestart:

  bsv.setRestart();

  break;

  }

  }

  }

  }

  < ?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"

  >

  < LinearLayout

  android:orIEntation="horizontal"

  android:layout_width="fill_parent"

  android:layout_height="wrap_content"

  >

  < Button android:id="@+id/butStop"

  android:text="stop"

  android:layout_height="wrap_content"

  android:layout_width="wrap_content"

  >

  < /Button>

  < Button android:id="@+id/butStart"

  android:text="Start"

  android:layout_height="wrap_content"

  android:layout_width="wrap_content"

  >

  < /Button>

  < Button android:id="@+id/butRestart"

  接上頁

  android:text="ReStart"

  android:layout_height="wrap_content"

  android:layout_width="wrap_content"

  >

  < /Button>

  < /LinearLayout>

  < FrameLayout

  android:layout_width="fill_parent"

  android:layout_height="wrap_content">

  < cn.edu.heut.zcl.BallSurfaceVIEw

  android:id="@+id/ballSurfaceVIEw"

  android:layout_width="fill_parent"

  android:layout_height="fill_parent">

  < /cn.edu.heut.zcl.BallSurfaceVIEw>

  < /FrameLayout>

  < /LinearLayout>

  有問題的留言,籃球運動是直接修改的上一節的例子,需要代碼的留下郵箱。

  1. 上一頁:
  2. 下一頁: