通常在繪製圖形界面時,咱們用到的是配置文件中的視圖,那麼咱們能不能定義本身須要的視圖呢?答案固然是能夠的,咱們能夠利用畫筆在畫布上本身繪製本身須要的視圖,在界面中引用過便可。然而,象畫圖這樣的操做,咱們不建議放在主UI線程中使用,咱們能夠利用繼承自SurfaceView或者繼承自View的方式去實現,咱們具體來看一下吧。
java
一:繼承自View完成自定義視圖
android
自定義視圖無疑就是繪製本身想要的視圖樣式,引用到工程中的過程。先來看看,如何自定義視圖?
canvas
1:自定義繼承自View的類,用來完成繪製。
ide
(1)添加構造方法,在構造方法中實例化畫筆,爲畫筆設置顏色
this
(2)重寫onDraw方法:參數爲畫布,能夠設置畫布的背景色,完成圖形的繪製等spa
//自定義視圖繼承自View public class MyView extends View{ private Paint paint;//聲明畫筆 public MyView(Context context) { super(context); paint = new Paint();//實例化畫筆 paint.setColor(Color.GREEN);//設置畫筆的顏色 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.WHITE);//設置畫布的背景色 //繪製矩形,參數(起始點x座標,起始點y座標,寬度,高度,畫筆對象) canvas.drawRect(10, 10, 100, 100, paint); } } |
2:在主界面的onCreate方法中引入自定義的視圖對象
線程
setContentView(new MyView(this)); |
3:結果:在主界面上繪製出了自定義的視圖樣式,以下
orm
二:應用繼承自View實現矩形塊的」必定一動「對象
1:添加構造方法,完成畫筆的初始化與屬性的設置blog
public MyRect(Context context) { super(context); paint.setColor(Color.GREEN); } |
2:繼承自View的類中的onDraw方法中,實現矩形的繪製
private float x = 0;// 起始x,y座標 private float y = 0; private float speedx = 50;// 矩形的寬與高 private float speedy = 50; private float addy = 2;// 每次移動時,x,y的增量值 private float addx = 2; // 設置畫布的背景色 canvas.drawColor(Color.WHITE); // 矩形的繪製 canvas.drawRect(x, y, x + speedx, y + speedy, paint); y += addy;// y座標值得變化 if (y < 0) {// 若y的上邊界超出了正值的範圍,跑到了手機屏幕的上方 addy = Math.abs(addy);// 則讓他的增量值爲+,向下跑 } if (y > getHeight() - speedy) {// 若是y的下邊界超出了屏幕範圍 addy = -Math.abs(addy);// 則讓他的增量值爲負,向上跑 } x += addx;// x座標值得變化 if (x < 0) {// 若x的左邊界超出了正值的範圍,跑到了手機屏幕的左方 addx = Math.abs(addx); } if (x > getWidth() - speedx) {// 若是x的右邊界超出了屏幕範圍 addx = -Math.abs(addx);// 則讓他的增量值爲負,向左跑 } |
3:建立Handler對象,實現Handler對象,在其中的handleMessage方法中實現重繪
private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { invalidate();// 重畫 }; }; |
4:添加計時器的啓動與終止方法,在啓動計時器中添加handler發送消息的方法
// 計時器的啓動 public void startTimer() { timer = new Timer(); task = new TimerTask() { @Override public void run() { // 發送消息 handler.sendEmptyMessage(0); } }; // 啓動計時器 timer.schedule(task, 100, 10); } // 終止計時器 public void stopTimer() { timer.cancel(); } |
5:主界面中,對自定義視圖添加OnTouchListener監聽,根據觸發的動做,實現」必定一動「的效果
public class MainActivity extends Activity implements OnTouchListener { private MyRect myRect;// 聲明自定義視圖 private int flag = 0;// 標誌 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); myRect = new MyRect(this);// 實例化自定義視圖 setContentView(myRect);// 添加視圖 myRect.setOnTouchListener(this);// 加載監聽 } @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN:// 是否是按下操做 if (flag == 0) {// 如果第一次單擊 myRect.startTimer();// 啓動,讓他走 flag = 1;// 更改標誌 }else if(flag==1){//若再次單擊 myRect.stopTimer();//則中止,不讓他動 flag=0;//修改標誌 } break; } return true;//注意,只有true的時候纔會觸發 } } |
6:結果:經過這種方法,實現矩形「必定一動」效果。能夠自行試試。
三:繼承自SurfaceView實現的自定義視圖
普通的繪製靜態圖形的操做還好,可是若是繪製動態或者更耗時的操做時,咱們並不建議將他們直接放置在主UI線程中,咱們繼承自SurfaceView就是本身建立了一個線程,在這個線程中去完成操做,顯得更好一些。
應用:咱們利用這種方法實現矩形的自由移動。
1:繼承自SurfaceView,並實現SurfaceHolder.Callback接口,重寫其中的三個方法
public class MySurface extends SurfaceView implements SurfaceHolder.Callback |
(1)surfaceCreated方法:當SurfaceView第一次建立時觸發的方法,主要完成初始化的工做,一搬不要在這裏完成繪製的操做
(2)surfaceChanged方法:當Surface的狀態發生變化時,觸發的方法
(3)surfaceDestoryed方法:當Surface銷燬前觸發的狀態,用於清理資源。
2:添加構造方法,實現畫筆的初始化及屬性設置,並添加回調
public MySurface(Context context) { super(context); paint.setColor(Color.GREEN);//畫筆的顏色設置 getHolder().addCallback(this);//添加回調 } |
3:自定義繪圖方法,完成矩形的繪製
private float x=0;//起始x,y座標 private float y=0; private float speedx=50;//矩形的寬與高 private float speedy=50; private float addy = 2;//每次移動時,x,y的增量值 private float addx=2; public void draw(){ //鎖定畫布,全部的繪圖操做,都要在鎖定於解鎖之間完成,不然出錯 Canvas canvas= getHolder().lockCanvas(); //設置畫布的背景色 canvas.drawColor(Color.WHITE); //矩形的繪製 canvas.drawRect(x, y, x+speedx, y+speedy,paint); y +=addy;//y座標值得變化 if(y<0){//若y的上邊界超出了正值的範圍,跑到了手機屏幕的上方 addy = Math.abs(addy);//則讓他的增量值爲+,向下跑 } if(y>getHeight()-speedy){//若是y的下邊界超出了屏幕範圍 addy = -Math.abs(addy);//則讓他的增量值爲負,向上跑 } x +=addx;//x座標值得變化 if(x<0){//若x的左邊界超出了正值的範圍,跑到了手機屏幕的左方 addx = Math.abs(addx); } if(x>getWidth()-speedx){//若是x的右邊界超出了屏幕範圍 addx = -Math.abs(addx);//則讓他的增量值爲負,向左跑 } //解鎖畫布 getHolder().unlockCanvasAndPost(canvas); } |
4:自定義定時器的啓動與暫停,並在計時器中調用繪圖方法
//計時器的啓動 public void startTImer(){ timer = new Timer();//實例化計時器 task = new TimerTask() { @Override public void run() { draw();//調用繪圖方法 } }; //啓動計時器 timer.schedule(task, 100,10); } //中止計時器 public void stopTimer(){ timer.cancel(); } |
5:將啓動計時器,關閉計時器的方法的引用添加到接口中重寫的三個方法中(注意引用的位置)
// 調用啓動計時器的方法 @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { startTImer(); } @Override public void surfaceCreated(SurfaceHolder holder) { } // 調用終止計時器的方法 @Override public void surfaceDestroyed(SurfaceHolder holder) { stopTimer(); } |
6:結果:實現了綠色矩形塊在屏幕範圍內的自由移動。