通常在绘制图形界面时,咱们用到的是配置文件中的视图,那么咱们能不能定义本身须要的视图呢?答案固然是能够的,咱们能够利用画笔在画布上本身绘制本身须要的视图,在界面中引用过便可。然而,象画图这样的操做,咱们不建议放在主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:结果:实现了绿色矩形块在屏幕范围内的自由移动。