一般在绘制图形界面时,我们用到的是配置文件中的视图,那么我们能不能定义自己需要的视图呢?答案当然是可以的,我们可以利用画笔在画布上自己绘制自己需要的视图,在界面中引用过即可。然而,象画图这样的操作,我们不建议放在主UI线程中使用,我们可以利用继承自SurfaceView或者继承自View的方式去实现,我们具体来看一下吧。
一:继承自View完成自定义视图
自定义视图无疑就是绘制自己想要的视图样式,引用到工程中的过程。先来看看,如何自定义视图?
1:自定义继承自View的类,用来完成绘制。
(1)添加构造方法,在构造方法中实例化画笔,为画笔设置颜色
(2)重写onDraw方法:参数为画布,可以设置画布的背景色,完成图形的绘制等
//自定义视图继承自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:结果:在主界面上绘制出了自定义的视图样式,如下

二:应用继承自View实现矩形块的”一定一动“
1:添加构造方法,完成画笔的初始化与属性的设置
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:结果:实现了绿色矩形块在屏幕范围内的自由移动。
自定义视图很有用处,我们得熟记于心哦。。。
转载于:https://blog.51cto.com/cinderella7/1296185