最近有需求需要画一个房子,要求能表达通风 ,显示温度和时间,借此机会,搞一个自定义控件
先看效果图,废话少说进入正题
1 先继承View 创建一个自定义控件
public class House extends View { public House(Context context) { super(context); init(context, null, 0); } public House(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs,0); } public House(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } public void init(Context context, AttributeSet attrs, int defStyle){ } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); } }1View的三个构造函数 2 onMeasure 3 onDraw 运行顺序依次123
基础做好了,然后准备一个画笔,放在init里
Paint paint; paint = new Paint(); paint.setColor(Color.WHITE); paint.setAntiAlias(true);//抗锯齿 paint.setTextSize(16);然后准备三张图,可以构成动态图,放在init里,顺便把它们放在数组中
bitmap1= BitmapFactory.decodeResource(getResources(), R.drawable.house1); bitmap2= BitmapFactory.decodeResource(getResources(), R.drawable.house2); bitmap3= BitmapFactory.decodeResource(getResources(), R.drawable.house3); data[0] = bitmap1; // 第一个元素 data[1] = bitmap2; // 第二个元素 data[2] = bitmap3;计算控件大小 ,在onMeasure 方法中执行,单位是像素,可以自己打印出来增加印象
height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);我们要求把动态图片摆放在控件的正中央这时候就要计算了。我们用的画图方法是
canvas.drawBitmap(Bitmap bitmap, float left, float top, @RecentlyNullable Paint paint);第一个参数很简单,就是图片,第二个参数表示距离父布局左边多长, 第三个显然就是距离父布局上边沿多远 ,第四个参数为画笔
那么,我们需要把图片放在整个view中间,就需要知道图片的长宽多少,我们用到这个方法
bitmap1.getWidth(), bitmap1.getHeight()我们的View 大小为
width 和 height知道了两者的大小,根据canvas.drawBitmap 的参数说明可以计算得到 当
left = width / 2-(bitmap1.getWidth()/2)
top = height / 2-(bitmap1.getHeight()/2),时 图片会居中显示
所以我们在
onDraw 这个方法里画上bitmap canvas.drawBitmap(data[position], width / 2-(bitmap1.getWidth()/2), height / 2-(bitmap1.getHeight()/2), paint);然后我们还需要时间和温度
这时候需要用到 canvas.drawText ( String text, float x, float y, Paint paint)这个方法
参数和上面差不多,就不多解释了 看代码
paint.setTextSize(width/15); paint.setStyle(Paint.Style.STROKE); canvas.drawBitmap(data[position], width / 2-(bitmap1.getWidth()/2), height / 2-(bitmap1.getHeight()/2), paint); canvas.drawText(Temp, width/2-paint.getTextSize(), height/2-paint.getTextSize(), paint); paint.setTextSize(width/20); canvas.drawText(TimeDate, width/2-( 3*paint.getTextSize()), height/2, paint);上面代码可以看出文字在View居中。 值得注意的是下面这个乘以3 的,因为我们知道时间是 这个格式
11:59 星期三前面的11:59 大概有三个字的大小,所以要乘3 。这样我们就得到一开始的效果图了
还剩最后一个问题,怎么让图片动起来,像帧动画一样一帧一帧播放
这时候我们需要用到定时器Timer ,有个方法是
schedule(TimerTask task, long delay, long period) //第一个参数代表 执行任务事件 //第二个参数代表 延时几秒开始操作 单位毫秒 //第三个参数代表 每间隔几秒开始就执行一次 单位毫秒
创建一个任务事件类
private class InputCheckTimerTask extends TimerTask { @Override public void run() { position++; if (position>2){ position=0; } invalidate(); } }然后再创建一个设置设置图片的方法
public void setPosition(){ if (mTimer == null) mTimer = new Timer(); //第一个参数代表 执行任务事件 //第二个参数代表 延时几秒开始操作 单位毫秒 //第三个参数代表 每间隔几秒开始就执行一次 单位毫秒 mTimer.schedule(mTask, 0, 1000); }顺便再创建两个方法,让时间和日期可以更改
public void setTemp(String string){ Temp = string; invalidate(); } public void setTimeDate(String string){ TimeDate = string; invalidate(); }这样就做完了一个简单的动态吹风的房间了,我们来看一下最终代码
package com.davell.ventilationSystem.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.util.AttributeSet; import android.util.Log; import android.view.View; import com.davell.ventilationSystem.R; import java.util.Timer; import java.util.TimerTask; public class House extends View { int height; int width; Paint paint; Bitmap bitmap1,bitmap2,bitmap3; Bitmap data[] = new Bitmap[3]; /** * 输入检查任务,即 要重复的事件 */ InputCheckTimerTask mTask= new InputCheckTimerTask(); /** * 定时器 */ Timer mTimer = null; int position = 0; String Temp = "88°C"; String TimeDate = "11:59 星期三"; public House(Context context) { super(context); init(context, null, 0); } public House(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs,0); } public House(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); Log.e("House","onMeasure" ); height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); } public void init(Context context, AttributeSet attrs, int defStyle){ Log.e("House","init" ); paint = new Paint(); paint.setColor(Color.WHITE); paint.setAntiAlias(true); paint.setTextSize(16); bitmap1= BitmapFactory.decodeResource(getResources(), R.drawable.house1); bitmap2= BitmapFactory.decodeResource(getResources(), R.drawable.house2); bitmap3= BitmapFactory.decodeResource(getResources(), R.drawable.house3); // bitmap1.setHeight(); data[0] = bitmap1; // 第一个元素 data[1] = bitmap2; // 第二个元素 data[2] = bitmap3; setPosition(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.e("House","onDraw" ); paint.setTextSize(width/15); paint.setStyle(Paint.Style.STROKE); canvas.drawBitmap(data[position], width / 2-(bitmap1.getWidth()/2), height / 2-(bitmap1.getHeight()/2), paint); canvas.drawText(Temp, width/2-paint.getTextSize(), height/2-paint.getTextSize(), paint); paint.setTextSize(width/20); canvas.drawText(TimeDate, width/2-( 3*paint.getTextSize()), height/2, paint); } public void setPosition(){ if (mTimer == null) mTimer = new Timer(); //第一个参数代表 执行任务事件 //第二个参数代表 延时几秒开始操作 单位毫秒 //第三个参数代表 每间隔几秒开始就执行一次 单位毫秒 mTimer.schedule(mTask, 0, 1000); } public int getPosition(){ return position; } private class InputCheckTimerTask extends TimerTask { @Override public void run() { position++; if (position>2){ position=0; } invalidate(); } } public void setTemp(String string){ Temp = string; invalidate(); } public void setTimeDate(String string){ TimeDate = string; invalidate(); } }有需要的小伙伴可以直接复制代码拿去用就行了