Android自定义View制作仪表盘界面

Android自定义View制作仪表盘界面,第1张

概述前言最近我跟自定义View杠上了,甚至说有点上瘾到走火入魔了。身为菜鸟的我自然要查阅大量的资料,学习大神们的代码,这不,前两天正好在郭神在微信公众号里推送一片自定义控件的文章――一步步实现精美的钟表界面

前言

最近我跟自定义view杠上了,甚至说有点上瘾到走火入魔了。身为菜鸟的我自然要查阅大量的资料,学习大神们的代码,这不,前两天正好在郭神在微信公众号里推送一片自定义控件的文章――一步步实现精美的钟表界面。正适合我这种菜鸟来学习,闲着没事,我就差不多依葫芦画瓢也写了一个自定义表盘VIEw,现在纯粹最为笔记记录下来。先展示下效果图:

下面进入正题

自定义表盘属性

老规矩,先在attrs文件里添加表盘自定义属性

<declare-styleable name="WatchVIEw"> <attr name="watchRadius" format="dimension"/> //表盘半径 <attr name="watchpadding" format="dimension"/> //表盘相对控件边框距离 <attr name="watchScalepadding" format="dimension"/> //刻度相对表盘距离 <attr name="watchScalecolor" format="color|reference"/> //常规刻度颜色 <attr name="watchScaleLength" format="dimension|reference"/> //常规刻度长度 <attr name="watchHourScalecolor" format="dimension|reference"/> //整点刻度颜色 <attr name="watchHourScaleLength" format="dimension|reference"/> //整点刻度长度 <attr name="hourPointcolor" format="color|reference"/> //时针颜色 <attr name="hourPointLength" format="dimension|reference"/> //时针长度 <attr name="minutePointcolor" format="color|reference"/> //分针颜色 <attr name="minutePointLength" format="dimension|reference"/> //分针长度 <attr name="secondPointcolor" format="color|reference"/> //秒针颜色 <attr name="secondPointLength" format="dimension|reference"/> //秒针长度 <attr name="timeTextSize" format="dimension|reference"/> //表盘字体大小 <attr name="timeTextcolor" format="color|reference"/> //表盘字体颜色 </declare-styleable>

在自定义view的构造方法种获取自定义属性

先将属性变量声明如下:

<span > /**表盘边距*/ private float mWatchpadding = 5; /**表盘与刻度边距*/ private float mWatchScalepadding = 5; /**表盘半径*/ private float mWatchRadius = 250; /**表盘刻度长度*/ private float mWatchScaleLength; /**表盘刻度颜色*/ private int mWatchScalecolor = color.BLACK; /**表盘整点刻度长度*/ private float mHourScaleLength = 8; /**表盘整点刻度颜色*/ private int mHourScalecolor = color.BLUE; /**表盘时针颜色*/ private int mHourPointcolor = color.BLACK; /**表盘时针长度*/ private float mHourPointLength = 100; /**表盘分针颜色*/ private int mMinutePointcolor = color.BLACK; /**表盘分针长度*/ private float mMinutePointLength = 130; /**表盘秒针颜色*/ private int mSecondPointcolor = color.RED; /**表盘秒针长度*/ private float mSecondPointLength = 160; /**表盘尾部指针长度*/ private float mEndPointLength; /**表盘数字颜色*/ private int mTimeTextcolor = color.BLACK; /**表盘数字大小*/ private int mTimeTextSize = 15;</span>

在构造方法种获取自定义属性

<span > public WatchVIEw(Context context,AttributeSet attrs) { super(context,attrs); TypedArray array = context.obtainStyledAttributes(attrs,R.styleable.WatchVIEw); int n = array.getIndexCount(); for (int i = 0;i<n;i++){ int attr = array.getIndex(i); switch (attr){ case R.styleable.WatchVIEw_watchRadius: mWatchRadius = array.getDimensionPixelSize(attr,MyUtil.dip2px(context,60)); break; case R.styleable.WatchVIEw_watchpadding: mWatchpadding = array.getDimensionPixelSize(attr,5)); break; case R.styleable.WatchVIEw_watchScalepadding: mWatchScalepadding = array.getDimensionPixelSize(attr,3)); break; case R.styleable.WatchVIEw_watchScaleLength: mWatchScaleLength = array.getDimensionPixelSize(attr,5)); break; case R.styleable.WatchVIEw_watchScalecolor: mWatchScalecolor = array.getcolor(attr,color.parsecolor("#50000000")); break; case R.styleable.WatchVIEw_watchHourScaleLength: mHourScaleLength = array.getDimensionPixelSize(attr,10)); break; case R.styleable.WatchVIEw_watchHourScalecolor: mHourScalecolor = array.getcolor(attr,color.BLACK); break; case R.styleable.WatchVIEw_hourPointLength: mHourPointLength = array.getDimensionPixelSize(attr,35)); break; case R.styleable.WatchVIEw_hourPointcolor: mHourPointcolor = array.getcolor(attr,color.BLACK); break; case R.styleable.WatchVIEw_minutePointLength: mMinutePointLength = array.getDimensionPixelSize(attr,40)); break; case R.styleable.WatchVIEw_minutePointcolor: mMinutePointcolor = array.getcolor(attr,color.BLACK); break; case R.styleable.WatchVIEw_secondPointLength: mSecondPointLength = array.getDimensionPixelSize(attr,50)); break; case R.styleable.WatchVIEw_secondPointcolor: mSecondPointcolor = array.getcolor(attr,color.BLUE); break; case R.styleable.WatchVIEw_timeTextSize: mTimeTextSize = array.getDimensionPixelSize(attr,15)); break; case R.styleable.WatchVIEw_timeTextcolor: mTimeTextcolor = array.getcolor(attr,color.BLACK); break; } } array.recycle(); }</span>

设置控件大小

这里当然就是重写onMeasure方法啦,这里我们处理的简单点,如下面代码所示,当我们将控件的宽高都设定为wrap_content(即MeasureSpec.UnspecIFED)时,我们将宽高设定为默认值(wrapContentSize)和圆盘半径+圆盘边距(mWatchRadius+mWatchpadding)之间取最大值,其他情况下就取系统自取值。当然作为一个严谨的控件,仅仅这样处理肯定是不行的。项目中,我们要根据我们的需求自行修改里面的代码以适配。

<span > @OverrIDe protected voID onMeasure(int wIDthMeasureSpec,int heightmeasureSpec) { int wrapContentSize = 1000; int wIDthSize = MeasureSpec.getSize(wIDthMeasureSpec); int wIDthMode = MeasureSpec.getMode(wIDthMeasureSpec); int heightSize = MeasureSpec.getSize(heightmeasureSpec); int heightmode = MeasureSpec.getMode(heightmeasureSpec); if (wIDthMode == MeasureSpec.UnspecIFIED && heightmode == MeasureSpec.UnspecIFIED){ wrapContentSize = (int) Math.max(wrapContentSize,mWatchRadius+mWatchpadding); setMeasuredDimension(wrapContentSize,wrapContentSize); }else { setMeasuredDimension(wIDthSize,heightSize); } }</span>

重写onDraw方法

来到最关键真正画表盘时刻了。一步一步来,首先初始化我们的画笔(我的习惯,写一个initPaint方法)

<span > private voID initPaint(){ mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setcolor(color.WHITE); mPaint.setStyle(Paint.Style.FILL); }</span>

为了不显赘述,方便理解,我直接展示代码,在代码中解释

开画之前我们先将画笔移动到控件中心点位置,如下:

<span >@OverrIDe protected voID onDraw(Canvas canvas) { canvas.translate(getWIDth()/2,getHeight()/2); }</span>

第一步,画表盘

<span > /** * 画表盘 * @param canvas */ private voID paintWatchBoard(Canvas canvas){ initPaint(); canvas.save(); canvas.drawCircle(0,mWatchRadius,mPaint); //画圆盘 canvas.restore(); }</span>

注:每次画图之前都要先调用canvas.save()方法,保存画笔属性,画完之后要调用canvas.restore()方法,重置画笔属性

这里就不一一展示每次画完之后的效果图了。

第二步,画刻度+整点时间数字(刻度从12点方向开始画)

<span > /** * 画刻度及整点数字 * @param canvas */ private voID paintScale(Canvas canvas){ int lineLength; //刻度线长度 canvas.save(); for (int i = 0;i<60;i++){ if (i%5 == 0){//整点刻度下画笔相关属性 mPaint.setstrokeWIDth(MyUtil.dip2px(getContext(),1.5f)); mPaint.setcolor(mHourScalecolor); lineLength = MyUtil.dip2px(getContext(),8); canvas.drawline(0,-mWatchRadius+mWatchScalepadding,-mWatchRadius+mWatchScalepadding+lineLength,mPaint); mPaint.setcolor(mTimeTextcolor); mPaint.setTextSize(mTimeTextSize); canvas.drawText(mTimes[i/5],-mTimeTextSize/2,-mWatchRadius+mWatchScalepadding + lineLength+mTimeTextSize,mPaint);//整点的位置标上整点时间数字 }else {//非整点刻度下画笔相关属性 mPaint.setstrokeWIDth(MyUtil.dip2px(getContext(),0.8f)); mPaint.setcolor(mWatchScalecolor); lineLength = MyUtil.dip2px(getContext(),5); canvas.drawline(0,mPaint); } canvas.rotate(6);//每次画完一个刻度线,画笔顺时针旋转6度(360/60,相邻两刻度之间的角度差为6度) } canvas.restore(); }</span>

其中,整点数字我用了罗马数字来表示

<span >private String[] mTimes = {"XII","Ⅰ","Ⅱ","Ⅲ","Ⅳ","Ⅴ","Ⅵ","Ⅶ","Ⅷ","Ⅸ","Ⅹ","XI"};</span>

 第三步,画时针、分针、秒针以及其它修饰图

考虑到时针、分针和秒针大小长度各不一样,我这里特意定义了三支画笔来分别画时针、分针和秒针。

同样的,先初始化指针画笔:

<span >/** * 初始化指针 */ private voID initPointPaint(){ mHourPaint = new Paint(); mHourPaint.setAntiAlias(true); mHourPaint.setStyle(Paint.Style.FILL); mHourPaint.setstrokeWIDth(16); mHourPaint.setcolor(mHourPointcolor); mMinutePaint = new Paint(); mMinutePaint.set(mHourPaint); mMinutePaint.setstrokeWIDth(12); mMinutePaint.setcolor(mMinutePointcolor); mSecondPaint = new Paint(); mSecondPaint.set(mHourPaint); mSecondPaint.setstrokeWIDth(7); mSecondPaint.setcolor(mSecondPointcolor); mEndPointLength = mWatchRadius/6; //(修饰部分)指针尾部长度,定义为表盘半径的六分之一 }</span> 

画指针

<span >/** * 画指针 * @param canvas */ private voID paintPoint(Canvas canvas){ initPointPaint(); Calendar c = Calendar.getInstance(); //取当前时间 int hour = c.get(Calendar.HOUR_OF_DAY); int minute = c.get(Calendar.MINUTE); int second = c.get(Calendar.SECOND); //绘制时针 canvas.save(); canvas.rotate(hour*30); canvas.drawline(0,-mHourPointLength,mHourPaint); canvas.drawline(0,mEndPointLength,mHourPaint); canvas.restore(); //绘制分针 canvas.save(); canvas.rotate(minute*6); canvas.drawline(0,-mMinutePointLength,mMinutePaint); canvas.drawline(0,mMinutePaint); canvas.restore(); //绘制秒针 canvas.save(); canvas.rotate(second*6); canvas.drawline(0,-mSecondPointLength,mSecondPaint); canvas.drawline(0,mSecondPaint); canvas.restore(); }</span>

OK,该有的差不多都有了,直接在onDraw中调用吧

<span >@OverrIDe protected voID onDraw(Canvas canvas) { canvas.translate(getWIDth()/2,getHeight()/2); paintWatchBoard(canvas); //画表盘 paintScale(canvas); //画刻度 paintPoint(canvas); //画指针 canvas.drawCircle(0,15,mSecondPaint); //为了美观,也让表盘更接近我们显示生活中的样子,我在圆盘中心画了一个大红圆点装饰秒针 postInvalIDateDelayed(1000); //每隔一秒钟画一次 }</span>

(⊙v⊙)嗯,自定义view大功告成,我们在布局文件里调用看下效果吧

<span ><?xml version="1.0" enCoding="utf-8"?> <relativeLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" xmlns:zhusp="http://schemas.androID.com/apk/res-auto" androID:layout_wIDth="match_parent" androID:layout_height="match_parent" androID:background="@color/colorAccent"> <com.wondertek.propertyanimatordemo.WatchVIEw androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" zhusp:timeTextSize="20dp" zhusp:watchRadius="150dp" zhusp:hourPointLength="80dp" zhusp:minutePointLength="100dp" zhusp:secondPointLength="115dp"/> </relativeLayout></span>

最后我这里的静态效果是这样的:

总结

以上是内存溢出为你收集整理的Android自定义View制作仪表盘界面全部内容,希望文章能够帮你解决Android自定义View制作仪表盘界面所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/web/1147828.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存