最近有需求需要画一个房子,要求能表达通风 ,显示温度和时间,借此机会,搞一个自定义控件
先看效果图,废话少说进入正题
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();
}
}
有需要的小伙伴可以直接复制代码拿去用就行了