1. 程式人生 > >Android碰撞的小球,密集恐懼症者謹慎

Android碰撞的小球,密集恐懼症者謹慎

今天又溫習了一遍Java的程序。正好用Android寫了一個小Demo,具體就是在手機螢幕上顯示多個運動的小球,小球碰到手機螢幕邊緣會自動彈回。大概就是下面圖中顯示的:


該本主要的結束的是自定義View封裝,View檢視繪製,通過xml檔案自定義View屬性並設定屬性,多執行緒Thread,小球碰撞彈回簡單演算法。

下面是製作這個Demo的簡單步驟:

step1:自定義一個View抽象類,它封裝了View類的基本方法,以及多執行緒的建立和操作方法。具體程式碼如下:

<span style="font-size:12px;">package com.example.constumeview;
import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;
public abstract class BaseCustomeView extends View {
	private MyThread myThread = null;
	private class MyThread extends Thread{
		@Override
		public void run() {
			while(true){
				logicalDo();
				postInvalidate(); //通知更新介面,會重新呼叫onDraw()函式
				try{
					sleep(80);
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
	}
	public abstract void logicDo(); //邏輯處理方法
	public abstract void drawSub(Canvas canvas); //繪畫內容程式碼
	public abstract void initView();
	@Override
	protected void onDraw(Canvas canvas) {
		if(myThread == null){  //第一次呼叫onDraw()方法的時候會建立一個執行緒,用來實現小球的碰撞彈回
			initView();<span style="white-space:pre">			</span>//初始化View方法
			myThread = new MyThread();
			myThread.start();    //啟動執行緒
		}else{ 
			drawSub(canvas);    //如果執行緒以建立,則呼叫繪製方法
		}
	}
	public BaseCustomeView(Context context) {
		super(context);
	}
	public BaseCustomeView(Context context, AttributeSet attrs) {
		super(context, attrs);
	}
}
</span>

下面我對View的兩個構造方法View(Context context)和View(Context context,AttributeSet attrs)解釋一下。第一個View(Context context)只有一個上下文context的引數,一般在程式碼(.javawenjian)中建立View進行呼叫,比如View  view = new View(this)。第二個構造方法View(Context context,AttributeSet attrs)有兩個引數,其中attrs是View的屬性集合。一般在佈局建立View物件時進行呼叫(.xml檔案)。

step2:然後重寫一個MyCustomeView類,繼承剛才定義的抽象類BaseCustomeView。並實現抽象方法initView()、logicalDo()、drawSub()方法。具體程式碼如下:
<span style="font-size:12px;">package com.example.constumeview;
import java.util.Random;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.util.AttributeSet;
public class MyCustomeView extends BaseCustomeView {
	private Paint paint = new Paint();
    private int ballNumber = 1;   //定義小球個數,預設為1個,通過xml自定義屬性進行設定,詳細看後面
    private PointF[] ballCenter = null;    //儲存各個小球的圓心座標
    private float ballRadius = 4.0f;   //定義小球半徑,通過xml自定義設定,看後面解釋
    private int viewWidth = 0;  //手機螢幕寬度
    private int viewHeight = 0; //手機螢幕高度
    private float[] xspace;   //儲存各個小球橫向運動速度,每個小球在橫向和縱向運動的速度是不同
    private float[] yspace;//儲存各個小球縱向的運動速度
	public MyCustomeView(Context context) {//程式碼中解析
		super(context);
	}

	public MyCustomeView(Context context, AttributeSet attrs) {//佈局中解析屬性
		super(context, attrs);
		TypedArray typeArray = context.obtainStyledAttributes(attrs,R.styleable.NumberText);
		ballNumber = typeArray.getInt(R.styleable.NumberText_ballNumber, 1);//獲得小球個數
		ballRadius = typeArray.getFloat(R.styleable.NumberText_ballRadius, 4.0f);//獲得小球半徑
		typeArray.recycle();//回收TypeArray資源
		productBallCenter();  //產生各個小球的圓心位置
		setBackgroundColor(Color.WHITE);//設定View背景色為白色
	}
	@Override
	public void logicDo() {//小球碰撞彈回簡單演算法
		for(int i=0;i<ballNumber;i++){
			if((ballCenter[i].x-ballRadius)<0){  //如果小球到達螢幕左邊緣,設定<span style="font-family: Arial, Helvetica, sans-serif;">ballCenter[i].x = ballRadius;</span>
				xspace[i] = 0-xspace[i];
				ballCenter[i].x = ballRadius;
			}else if((ballCenter[i].x+ballRadius)>viewWidth){//如果小球到達螢幕右邊緣
				xspace[i] = 0-xspace[i];
				ballCenter[i].x = viewWidth-ballRadius;
			}
			else if((ballCenter[i].y-ballRadius)<0){//如果小球達到螢幕上邊緣
				yspace[i] = 0-yspace[i];
				ballCenter[i].y = ballRadius;
			}else if((ballCenter[i].y+ballRadius)>viewHeight){//如果小球到達螢幕下邊緣
				yspace[i] = 0-yspace[i];
				ballCenter[i].y = viewHeight-ballRadius;
			}
			else{<span style="white-space:pre">			</span>//預設正常情況下
				ballCenter[i].x = ballCenter[i].x+xspace[i];
				ballCenter[i].y = ballCenter[i].y+yspace[i];
			}
		}
	}
	@Override
	public void drawSub(Canvas canvas) {//以圓心座標繪製每個小球在螢幕中的位置
		for(int i=0;i<ballNumber;i++){
			/*Random random = new Random();
			int r = random.nextInt(256);
			int g = random.nextInt(256);
			int b = random.nextInt(256);
			paint.setARGB(255,r, g, b);*/<span style="white-space:pre">		</span>//隨機產生小球的顏色,這裡我註釋了,用的是全黑
			canvas.drawCircle(ballCenter[i].x, ballCenter[i].y, ballRadius, paint);
		}
	}
	public void productBallCenter(){  //隨機初始化小球的圓心和小球運動速度,只在initView中呼叫一次
		ballCenter = new PointF[ballNumber];
		xspace = new float[ballNumber];
		yspace = new float[ballNumber];
		Random random = new Random();
		float xpoint = 0;
		float ypoint = 0;
		for(int i=0;i<ballNumber;i++){
			xpoint = random.nextFloat()*viewWidth+ballRadius;
			ypoint = random.nextFloat()*viewHeight+ballRadius;
			ballCenter[i] = new PointF(xpoint,ypoint);
			xspace[i] = random.nextFloat()*ballRadius+1;
			yspace[i] = random.nextFloat()*ballRadius+1;
		}
	}
	@Override
	public void initView() {  //初始化View方法,準備工作
		viewWidth = getWidth();  
		viewHeight = getHeight();
		productBallCenter();
	}
}
</span>
程式的執行過程我在註釋中寫得很詳細了,現在我主要介紹一下怎麼在xml中自定義View的屬性。比如在上面程式中ballNumber和ballRadius屬性是同xml檔案設定的,以及我們自定義的MyCustomeView物件也是通過xml進行初始化的。下面是我的xml檔案中程式碼,只有幾行:
<LinearLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    xmlns:yourname="http://schemas.android.com/apk/res/com.example.constumeview"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <com.example.constumeview.MyCustomeView 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        yourname:ballNumber="500"
        yourname:ballRadius="10.0"/>
</LinearLayout>
下面是具體步驟:

1.首先在自定義類中宣告你要在xml檔案設定的屬性,比如我在MyCustomeView中聲明瞭ballNumber和ballRadius屬性。

2.在values資料夾中建立一個attrs.xml檔案,在裡面宣告你要在xml檔案中使用的屬性,如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="NumberText">
        <attr name="ballNumber" format="integer"/>
        <attr name="ballRadius" format="float"/>
    </declare-styleable>
</resources>
name為屬性名,format為屬性的資料型別。

3.在主檢視佈局檔案中(我這裡是預設的activity_main.xml檔案),設定屬性的值,程式碼我已經貼在上面。

在主佈局中新增xmlns:yourname="http://schemas.android.com/apk/res/com.example.constumeview";

其中xmlns:yourname中xmlns是固定的,yourname可以自定義,不過設定屬性的時候要保持一致。後面的工具前面的http://schemas.android.com/apk/res/是不變的,後面的是你的工作空間包名。接下來就是設定屬性了。例如:yourname:ballNumber="500"  yourname:ballRadius="10.0".詳細看上面的程式碼部分哦。

4.最後貼上我入口程式MainActivity.java中的程式碼,其實什麼都沒有,只是為了保持專案的完整性,讀者好參考。

package com.example.constumeview;
import android.app.Activity;
import android.app.ActionBar;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}
到此一個滿螢幕都是碰撞小球的Demo就製作好了,密集恐懼症的人請將小球個數調少點哦。23333333