小白上手型自定义仪表盘

-摄于Shen Zhen OCT

我,是一个喜爱自由摄影的伪文艺情感泛滥的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一下吧。。。


小白上手型自定义仪表盘_第1张图片
@王先森Kenny

对了,之前就被坑过,自定义控件和父控件有很大的关系,最好用一个父控件包住自定义控件,这样比较好控制自定义控件的大小。



最后。。。

恩,第一次写,不管有人没人看,都记录一下吧,毕竟,










































没有毕竟!就是要记录下来!!!





你可能感兴趣的:(小白上手型自定义仪表盘)