我,是一个喜爱自由摄影的伪文艺情感泛滥的APP开发逗比。
次奥,说完上面那句话,我都不好意思说自己是个APP的开发逗比了。因为!我是闫肃的,额(⊙o⊙)…,不,是严肃的!
既然被定义到APP开发逗比,那我的第一炮就给Android开发了吧!王先森现在在某公司实习,恩,有老司机指教,有精致的下午茶,有长腿美女相伴。。。咳咳,这些统统没有!!!但是,既来之,则安之,虽然没有老司机,但是王先森是食脑嘅。
最近,公司安排了一个项目给我负责,没错,我们公司都是一个人负责一个项目,恩,切确的说应该是一个人负责多个项目,一个项目只有一个人负责,恩,就是这个关系。这个项目呢,适合车辆挂钩的,所以怎么会都和仪表盘挂上钩了,当然,我接到手的第一反应是上github上面搜索一下,看一下有木有可以用的控件,这将会大大缩短开发时间的,毕竟,我们只有两个星期的时间!!!找了一番之后,有是有,但是并不符合需求啊。后面想了想,还是弄自定义控件吧,于是乎,又是谷歌,又是百度的,查看了整整十页有木有,终于被我找到了,但是有些写的还是太复杂,代码也没有什么注释,理解还是比较费劲的。王先森也是花了一些时间才消化的。为了小小白(我是小白)的快速上手,这里还是说一下吧,老司机就直接把我扔在街角就好了。。。
好了,进入正题。
先看代码吧。
/**
* Created by Kenny on 2016/2/23 18:42.
* Desc:
*/
public class DashboardView extends View {
private static final String TAG = DashboardView.class.getSimpleName();
private Paint paint1; //画外面不完整圆和凸起的刻度画笔
private Paint paint2; //写字用的画笔
private Paint paint3; //用来画圆心的
private RectF r1; //换圆需要的范围
private float pointerAngle = 60;
private float mProgress = 35; //初始给一个刻度值
private int mMileage = 23541; //下面显示的里程数
private int mHeight; //自定义控件的高
private int mWidth; //自定义控件的宽 这两个挺重要的,为了屏幕的适配吧,我是这么理解的,看了好多文章,也问了同事。
private int range; //就是这个控件可以操控的一个范围
/**
* @param context
* @param attrs
*/
public DashboardView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
initview();
}
/**
*
*/
private void initview() {
// TODO Auto-generated method stub
paint1 = new Paint();
paint1.setColor(getResources().getColor(R.color.colorRadioButton)); //这种就是获取color.xml文件里面的颜色
paint1.setStyle(Paint.Style.STROKE); //设置画笔的风格,实心的,空心的,什么鬼,具体百度一下吧
paint1.setStrokeWidth(4);
paint1.setAntiAlias(true); //是否抗锯齿,这个重要,不信,你设置为false看看,丑哭你/(ㄒoㄒ)/~~
paint2 = new Paint();
paint2.setTextSize(16);
paint1.setStyle(Paint.Style.STROKE);
paint2.setColor(Color.BLACK); //这种就是直接用的自带的颜色了,但是一般都不用这种,毕竟颜色要喝主题想衬才和谐
paint2.setStrokeWidth(2);
paint3 = new Paint();
paint3.setAntiAlias(true); //设置画笔为无锯齿
paint3.setColor(getResources().getColor(R.color.colorRadioButton)); //设置画笔颜色
paint3.setStyle(Paint.Style.FILL); //这个就是设置实心的了
}
/**
* 设置指针指示
* 就是指针转动的幅度
*
* @param progress
*/
public void setProgress(int progress) {
mProgress = progress;
invalidate();
}
/**
* 设置里程,提供对外方法,可以操控仪表盘的里程显示
*/
public void setMileage(int mileage) {
mMileage = mileage;
invalidate();
}
//至于下面这个方法嘛~~~还是有很多细致的内容的,这里轻度注释一下吧。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
setMeasuredDimension(measureWidth(widthMeasureSpec),measureHeight(heightMeasureSpec));
range = Math.min(mHeight, mWidth) - 30;//获取最小值
r1 = new RectF(-range, -range, range, range); //四个参数前两个是左上角的坐标,右面两个是右下角的坐标
}
private int measureWidth(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec); //mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY(这种就是具体给定了值,比如说50dp什么的), MeasureSpec.AT_MOST(这种是最大值,就是没有指定,wrap_content)。
int specSize = MeasureSpec.getSize(measureSpec); //这个就是获取尺寸了
mWidth = DensityUtil.px2dip(getContext(), specSize); //获取得到的是px,这里我需要转换,所以转换成dp
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
} else {
// Measure the text
result = (int) getWidth();
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by
// measureSpec
result = Math.min(result, specSize);//
}
}
return specSize; //上面的都是实验,统统不要,我这里只返回了父控件传进来的大小
}
private int measureHeight(int measureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
mHeight = DensityUtil.px2dip(getContext(), specSize);
Log.i(TAG, "--specSize=" + specSize);
// mAscent = (int) mPaint.ascent();
if (specMode == MeasureSpec.EXACTLY) {
// We were told how big to be
result = specSize;
Log.i(TAG, "--EXACTLY=");
} else {
// Measure the text (beware: ascent is a negative number)
result = (int) getHeight();
Log.i(TAG, "--result=" + result);
if (specMode == MeasureSpec.AT_MOST) {
// Respect AT_MOST value if that was what is called for by
// measureSpec
Log.i(TAG, "--AT_MOST=");
result = Math.min(result, specSize);
}
}
Log.i(TAG, "--height=" + result);
return specSize;
}
/*
* (non-Javadoc)
*
* @see android.view.View#onDraw(android.graphics.Canvas)
* 画牛画马画美女,就靠它了!
*/
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.translate(canvas.getWidth() / 2, canvas.getHeight() / 2); // 将原点移到画布中心
canvas.drawText("km/h", -paint2.measureText("km/h", 0, "km/h".length()) / 2, -(range / 2), paint2); // km/h
String showMileage = String.valueOf(mMileage);
canvas.drawText(showMileage, -paint2.measureText(showMileage, 0, showMileage.length()) / 2, (range / 1.2f), paint2); // mileage
canvas.save();
canvas.rotate(-120, 0f, 0f); //这里这里,就是将整个画布选择,还有一个是只有一个参数的,那它默认的中心点就是原点了(屏幕左上角)
for (int i = 0; i < 9; i++) {
canvas.drawLine(0, -range, 0, -(range + 10), paint1);
canvas.drawText(i + "k", -paint2.measureText(i + "k", 0, (i + "k").length()) / 2, -(range + 20), paint2);
canvas.rotate(30, 0f, 0f); //循环画那个突出了的东东
}
canvas.restore();
canvas.drawArc(r1, 150, 240, false, paint1);
canvas.drawCircle(0, 0, 5, paint3);
canvas.rotate(pointerAngle + mProgress, 0f, 0f);
canvas.drawLine(0, 0, 0, range - 20, paint1);
}
}
最后上图!
(⊙o⊙)…
Android studio 大姨夫了
加上下面这个炒鸡简略的图YY一下吧。。。
对了,之前就被坑过,自定义控件和父控件有很大的关系,最好用一个父控件包住自定义控件,这样比较好控制自定义控件的大小。
最后。。。
恩,第一次写,不管有人没人看,都记录一下吧,毕竟,
没有毕竟!就是要记录下来!!!