Android的大多數控制項都是繼承自View的,因此在自訂控制項時一般也是繼承View類,但是對於高效的,遊戲層級的繪圖,或者是播放器等要求比較高的地方,普通的View類就有點吃不開了,這個時候就要用到SurfaceView類。因為比較進階,所以就該裝B,單純一個繼承自SurfaceView類是不行的,必須實現一個SurfaceHolder.Callback介面來指明SurfaceView建立、改變、刪除時的回調方法,並且在SurfaceView中通過一個SurfaceHolder對象來控制SurfaceView。
如果將該SurfaceView作為某個Activity的全屏View,則直接調用setContentView(new MyView());就好了;但若是作為螢幕View的一部份,就應該修改對應的layout XML檔案了,添加類似的布局代碼:
<com.android.sv.MyView
android:id="@+id/sv"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
其中com.example.fq.MyView為對應自訂類的全名。
由於預設的XML檔案解析方法是調用View的View(Context , AttributeSet )建構函式構造View,因此你的自訂SurfaceView中也應該有一個參數為(Context , AttributeSet )的建構函式,並且在建構函式中執行父類的對應函數super( Context , AttributeSet )。在繪圖時,必須首先用Canvas c=holder.lockCanvas();鎖定並獲得畫布,隨後進行繪製,再調用holder.unlockCanvasAndPost(c);將繪製內容進行呈現
下面是個例子運行圖:
主介面:
- public class MainActivity extends Activity {
-
- private MyView mSV=null;
- private Button mBtnOk;
- private Button mBtnCancle;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mSV=(MyView)findViewById(R.id.sv);
- mSV.setTag(true);
- mBtnOk=(Button)findViewById(R.id.btnok);
- mBtnOk.setOnClickListener(new OnClickListener() {
-
- public void onClick(View arg0) {
- // TODO Auto-generated method stub
- mSV.setTag(true);
- }
- });
-
- mBtnCancle=(Button)findViewById(R.id.btnCancel);
- mBtnCancle.setOnClickListener(new OnClickListener() {
-
- public void onClick(View arg0) {
- // TODO Auto-generated method stub
- mSV.setTag(false);
- }
- });
- }
- }
MyTest介面:
[java] view plaincopy
- public class MyView extends SurfaceView implements SurfaceHolder.Callback{
- private SurfaceHolder holder=null; //控制對象
- private Vector<Float> xs=new Vector<Float>();
- private Vector<Float> ys=new Vector<Float>();
- public MyView(Context context, AttributeSet attrs) {
- super(context, attrs);
- holder=getHolder();
- holder.addCallback(this);
- }
-
- public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
- // TODO Auto-generated method stub
-
- }
-
- public void surfaceCreated(SurfaceHolder arg0) {
- // TODO Auto-generated method stub
- new Thread(new MyLoop()).start();//在 View 中系統不允許主線程外的線程式控制制 UI .但是 SurfaceView 卻可以
- }
-
- public void surfaceDestroyed(SurfaceHolder arg0) {
- // TODO Auto-generated method stub
-
- }
- public void doDraw(Canvas canvas) {
- // TODO Auto-generated method stub
- super.onDraw(canvas);
- canvas.drawColor(Color.WHITE);//這裡是繪製背景
- Paint p=new Paint(); //筆觸
- p.setAntiAlias(true); //反鋸齒
- p.setColor(Color.BLACK);
- p.setStyle(Style.STROKE);
- int a=xs.size();
- for(int i=0;i<xs.size();i++)
- canvas.drawCircle(xs.elementAt(i),ys.elementAt(i),10, p);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // TODO Auto-generated method stub
- if(event.getAction()==MotionEvent.ACTION_DOWN){
- String a=this.getTag().toString();
- if(a.equals("true")){
- xs.add(event.getX());
- ys.add(event.getY());
- }
- }
- return true;
- }
-
- class MyLoop implements Runnable{
- //熟悉遊戲編程的應該很面熟吧,主迴圈
- public void run() {
- // TODO Auto-generated method stub
- while(true){
- try{
- Canvas c=holder.lockCanvas();
- doDraw(c);
- holder.unlockCanvasAndPost(c);
- Thread.sleep(20);
- }catch(Exception e){
-
- }
- }
- }
-
- }
- }
main.xml檔案:
[java] view plaincopy
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <com.android.sv.MyView
- android:id="@+id/sv"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- />
- <Button android:id="@+id/btnok"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="開啟繪圖"/>
- <Button android:id="@+id/btnCancel"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_toRightOf="@id/btnok"
- android:text="取消繪圖"/>
- </RelativeLayout>