摘要:先看效果原諒我的渣像素,進(jìn)度的刻度寬度顏色可以隨意設(shè)定項(xiàng)目地址實(shí)現(xiàn)起來并不難,通過本文,我們可以學(xué)到自定義屬性的使用。
先看效果(原諒我的渣像素),進(jìn)度的刻度、寬度、顏色可以隨意設(shè)定:
項(xiàng)目github地址: https://github.com/zhangke301...
實(shí)現(xiàn)起來并不難,通過本文,我們可以學(xué)到:
1、自定義屬性的使用。
2、shader的使用
3、自定義View中對(duì)onmeasure的處理
4、增深對(duì)PathMeasure工具類的了解
5、最主要的是對(duì)自定義View有個(gè)比較清晰的思路認(rèn)識(shí)
做這樣一個(gè)進(jìn)度效果,我們可以拆分如下步驟來實(shí)現(xiàn):
從外部圓環(huán)開始測(cè)量繪制;
再加入刻度條效果;
再加入刻度隨進(jìn)度增加而增加效果;
增加自定義屬性增加可定制性;
控件使用方法介紹
OK,有了這個(gè)思路,那我們開始吧:
1、測(cè)量繪制外部圓環(huán)
首先我們要開始繪制外部的圓環(huán),這步很簡(jiǎn)單,主要是使用canvas的drawArc()方法,
/* * @param oval 畫弧線矩形區(qū)域 * @param startAngle 開始的角度 * @param sweepAngle 劃過的角度 * @param useCenter 如果為true 為實(shí)心圓弧 * @param paint 畫筆 * / public void drawArc(RectF oval, float startAngle, float sweepAngle,boolean useCenter,Paint paint)
這個(gè)相對(duì)簡(jiǎn)單,主要是確定開始角度,并不斷增加繪制劃過角度,圓弧就出現(xiàn)在界面中了,這里需要注意的是RectF oval的大小確定:
在確定RectF oval之前,我們要先測(cè)量確定當(dāng)前控件的寬高,根據(jù)當(dāng)前控件的寬高來確定oval的合適大小。
測(cè)量當(dāng)前控件的大小一般我們?cè)趏nmeasure()方法中處理,resolveMeasured()方法傳遞兩個(gè)參數(shù),第一各參數(shù)為widthMeasureSpec或者h(yuǎn)eightMeasureSpec,第二個(gè)參數(shù)為期望值也就是默認(rèn)值。
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(resolveMeasured(widthMeasureSpec, nDesired), resolveMeasured(heightMeasureSpec, nDesired)); } /** * * @param measureSpec * @param desired * @return */ private int resolveMeasured(int measureSpec, int desired) { int result = 0; int specSize = MeasureSpec.getSize(measureSpec); switch (MeasureSpec.getMode(measureSpec)) { case MeasureSpec.UNSPECIFIED: // result = desired; break; case MeasureSpec.AT_MOST: //wrap-content result = Math.min(specSize, desired); break; case MeasureSpec.EXACTLY: //match-content default: result = specSize; } return result; }
在測(cè)量之后我們就可以來求oval的具體大小 ,我把這步操作放在了onSizeChanged方法中,求出最小一邊的一半減去圓環(huán)的寬度,得到圓弧的半徑,然后根據(jù)半徑以控件中心為中心繪制我們所需要的矩形區(qū)域。
radiu = (int) ((Math.min(getWidth(), getHeight()))/2-mPaint.getStrokeWidth()); oval.left = getWidth()/2-radiu; oval.top = getHeight()/2-radiu; oval.right = getWidth()/2+radiu; oval.bottom = getHeight()/2+radiu;
這樣下來,基本上就可以繪制比較理想的弧線了,在這里也把繪制中心文字也說下吧,主要通過getTextBounds()方法獲取文字區(qū)域的寬高,然后在drawText()方法中將坐標(biāo)進(jìn)行適當(dāng)偏移以使文字居中顯示。
String strProgressText = ""; if(mOnProgressListener !=null){//如果不為空 則為接口返回的值 strProgressText = mOnProgressListener.OnProgress(mMax, mProgress); }else{ strProgressText = mProgress+"/"+mMax; } mTextPaint.getTextBounds(strProgressText, 0, strProgressText.length(), bounds); canvas.drawText(strProgressText, oval.centerX()-bounds.width()/2, oval.centerY()+bounds.height()/2, mTextPaint);
最后還有一個(gè)小點(diǎn)就是漸變色的繪制,用的SweepGradient,我們可以看下Shader的子類,shader類是很強(qiáng)大的,類似與圓形圖片、漸變效果都可以用它來實(shí)現(xiàn),這里就不過多展開了:
SweepGradient sweepGradient = new SweepGradient(getWidth()/2, getHeight()/2, colors, null); p.setShader(sweepGradient);
到這里為止,我們的圓環(huán)已經(jīng)繪制好了,包括中間的文字以及圓環(huán)的漸變效果都已經(jīng)實(shí)現(xiàn)了,就是這樣的:
2、加入刻度效果
接下來要加入刻度效果,實(shí)現(xiàn)思路是這樣的,我先默認(rèn)實(shí)現(xiàn)兩個(gè)圓弧(注意這兩個(gè)圓弧只是我們假定添加的,并不是真正加在控件中顯示),然后獲取相同角度,根據(jù)相對(duì)位置獲取兩個(gè)圓環(huán)上的點(diǎn)進(jìn)行連線,將這兩個(gè)點(diǎn)連起的刻度線封裝成對(duì)象添加在集合中,最后在onDraw方法中遍歷集合,進(jìn)行繪制。
oval2 = new RectF();//內(nèi)環(huán) oval2.left = getWidth()/2-radiu/4f*3; oval2.top = getHeight()/2-radiu/4f*3; oval2.right = getWidth()/2+radiu/4f*3; oval2.bottom = getHeight()/2+radiu/4f*3; oval3 = new RectF();//外環(huán) oval3.left = getWidth()/2-radiu/8f*7; oval3.top = getHeight()/2-radiu/8f*7; oval3.right = getWidth()/2+radiu/8f*7; oval3.bottom = getHeight()/2+radiu/8f*7; //然后初始化數(shù)據(jù) /** * 初始化數(shù)據(jù) */ private void initData() { mLinesList.clear(); Path path = new Path(); Path path1 = new Path(); //從startAngle開始 繪制180角度 path.addArc(oval2, mStartAngle, mGraduationSweepAngle); path1.addArc(oval3, mStartAngle, mGraduationSweepAngle); PathMeasure pm = new PathMeasure(path, false); float itemLength = pm.getLength()/(nGraduationCount-1); PathMeasure pm1 = new PathMeasure(path1, false); float[] pos = new float[2]; float[] postemp = new float[2]; for (int i = 0; i < nGraduationCount; i++) { pm.getPosTan(itemLength*i, pos , null ); pm1.getPosTan(itemLength*i/pm.getLength()*pm1.getLength(), postemp , null); Line line = new Line(); line.p1.x = pos[0]; line.p1.y = pos[1]; line.p2.x = postemp[0]; line.p2.y = postemp[1]; mLinesList.add(line); } } //ondraw方法: for (int i = 0; i < mLinesList.size(); i++) { Line line = mLinesList.get(i); canvas.drawLine(line.p1.x, line.p1.y, line.p2.x, line.p2.y, mRollPaint); }
這里用到了PathMeasure這個(gè)輔助工具,這里簡(jiǎn)單講一下:
public PathMeasure() //path:需要測(cè)量的path forceClosed:是否關(guān)閉path public PathMeasure(Path path, boolean forceClosed) //指定需要測(cè)量的path public void setPath(Path path, boolean forceClosed) //返回當(dāng)前path的總長(zhǎng)度。 getLength() //返回值是boolean,如過path為空,則返回false 傳入?yún)?shù)有三個(gè): //distance:傳入距離起點(diǎn)的距離。 //pos[]:意思是position,分別對(duì)應(yīng)點(diǎn)的x,y坐標(biāo) //tan[]:獲取切線值,不常用。 public boolean getPosTan(float distance, float pos[], float tan[]) //返回一個(gè)處理好的matrix,但是這個(gè)matrix是以左上角作為旋轉(zhuǎn)點(diǎn),所以需要將這個(gè)點(diǎn)移動(dòng)到中心點(diǎn)。 其中一個(gè)參數(shù)flags,指這個(gè)martrix需要什么信息。flags的值有如下兩個(gè) PathMeasure.POSITION_MATRIX_FLAG:位置信息 pathMeasure.TANGENT_MATRIX_FLAG:切邊信息,方位角信息 public boolean getMatrix(float distance, Matrix matrix, int flags) //這個(gè)方法返回boolean,如果截取的長(zhǎng)度為0則返回false,否則為true。參數(shù)如下 //startD:起始距離 //stopD:終點(diǎn)距離 //dst:接收截取的path //startWithMoveTo:是否把截取的path,moveto到起始點(diǎn)。 public boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)
3、加入刻度隨進(jìn)度增加而增加效果,并增加進(jìn)度變化回調(diào)方便操作
加入刻度隨進(jìn)度增加而增加,我們可以這樣想,首先我總的刻度數(shù)是一定的,判斷劃過的角度占圓周的百分比,隨之就可以得到劃過刻度數(shù)占總刻度數(shù)的百分比,進(jìn)而就求出劃過的刻度數(shù)了。
for (int i = 0; i < Math.round(mSweepAngle*nGraduationCount/360f); i++) { if(i將劃過的刻度數(shù)用畫筆再繪制一次,隨進(jìn)度增加的刻度效果就出現(xiàn)啦!
/** * 設(shè)置進(jìn)度監(jiān)聽 * @param mOnProgressListener */ public void setOnProgressListener(OnProgressListener mOnProgressListener) { this.mOnProgressListener = mOnProgressListener; } /** * 用于外部判斷當(dāng)前進(jìn)度狀態(tài) */ interface OnProgressListener{ /** * 返回中間部分文字內(nèi)容 * @param max * @param progress * @return */ String OnProgress(int max,int progress); }設(shè)置回調(diào)監(jiān)聽,這樣在每次進(jìn)度變化的時(shí)候,可以隨意變化中間部分文字顯示的內(nèi)容。
4、增加自定義屬性增加可定制性
attrs.xml:
layout文件:
xmlns:app="http://schemas.android.com/apk/res-auto"獲取自定義屬性值:
TypedArray typedArray = getResources().obtainAttributes(attrs, R.styleable.LoadingStyle); mTextSize = (int) typedArray.getDimension(R.styleable.LoadingStyle_textSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics())); mStrokeWidth = (int) typedArray.getDimension(R.styleable.LoadingStyle_strokeWidth, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, getResources().getDisplayMetrics())); mGraduationWidth = (int) typedArray.getDimension(R.styleable.LoadingStyle_graduationWidth, mStrokeWidth/2); mTextColor = (int) typedArray.getColor(R.styleable.LoadingStyle_textColor, Color.BLACK); mGraduationBackgroundColor = (int) typedArray.getColor(R.styleable.LoadingStyle_graduationBackgroundColor, Color.BLACK); mStartAngle = (int) typedArray.getInt(R.styleable.LoadingStyle_startAngle, 180); mMax = (int) typedArray.getInt(R.styleable.LoadingStyle_max, 0); mProgress = (int) typedArray.getInt(R.styleable.LoadingStyle_progress, 0); nGraduationCount = (int) typedArray.getInt(R.styleable.LoadingStyle_graduationCount, 35); isShowGraduationBackground = typedArray.getBoolean(R.styleable.LoadingStyle_isShowGraduationBackground, true); isShowOutRoll = typedArray.getBoolean(R.styleable.LoadingStyle_isShowOutRoll, true); typedArray.recycle();5、使用方法
int[] colors = {0xFFE5BD7D, 0xFFFAAA64, 0xFFFFFFFF, 0xFF6AE2FD, 0xFF8CD0E5, 0xFFA3CBCB, 0xFFBDC7B3, 0xFFD1C299, 0xFFE5BD7D}; lv_loading.setTextColor(Color.BLACK);//設(shè)置中心文字顏色 lv_loading.setMax(500);//設(shè)置最大進(jìn)度 lv_loading.setShowGraduationBackgroundEnable(true);//是否顯示刻度背景 lv_loading.setGraduationBackgroundColor(Color.GRAY);//刻度的背景顏色 lv_loading.setStartAngle(180);//設(shè)置開始旋轉(zhuǎn)角度 lv_loading.setGraduationCount(10);//設(shè)置刻度數(shù) lv_loading.setGraduationWidth(5);//設(shè)置刻度的寬度 lv_loading.setOutColors(colors);//設(shè)置外部圓環(huán)顏色 lv_loading.setInnerGraduationColors(colors);//設(shè)置內(nèi)部刻度進(jìn)度顏色 lv_loading.setTextSize(35);//設(shè)置內(nèi)部文字字體大小 lv_loading.setShowOutRollEnable(false);//設(shè)置是否顯示外部進(jìn)度框 lv_loading.setOnProgressListener(new OnProgressListener() { @Override public String OnProgress(int max, int progress) { return progress*100f/max+"%"; } });項(xiàng)目github地址: https://github.com/zhangke301...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/65003.html
摘要:地址中文自定義能改變尺寸顏色滑塊圖片刻度圖片刻度文字和氣泡指示器,當(dāng)滑動(dòng)時(shí)顯示帶有進(jìn)度的指示器。給選擇圓角方角默認(rèn)兩端是圓角,可以設(shè)置為方形。滑塊下顯示進(jìn)度當(dāng)?shù)念愋蜑闀r(shí)可以設(shè)置滑動(dòng)后滑塊下顯示保留進(jìn)度。 IndicatorSeekBar showImg(https://segmentfault.com/img/remote/1460000011967195);showImg(https...
閱讀 1300·2021-11-24 09:39
閱讀 2672·2021-09-30 09:47
閱讀 1333·2021-09-22 15:15
閱讀 2419·2021-09-10 10:51
閱讀 1969·2019-08-30 15:55
閱讀 2982·2019-08-30 11:06
閱讀 903·2019-08-30 10:53
閱讀 840·2019-08-29 17:26