小白上手型自定义仪表盘

-摄于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一下吧。。。


@王先森Kenny

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



最后。。。

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










































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





最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容