效果图: 实现思路: 1。定义一个画外弧的画笔,使用画笔画出圆弧UI 2。定义一个画内圆(灰色)的画笔,使用画笔画出内圆UI 3。定义一个画圆点的画笔,使用画笔画出圆点UI 4。定义一个画文本的画笔,使用画笔画出文本的值 5。监听触摸事件,通过触摸事件计算和判断是否在圆弧上。 实现CustomVolumeProgressView自定义View,如下:importandroid。content。Cimportandroid。graphics。Cimportandroid。graphics。Pimportandroid。graphics。RectF;importandroid。util。AttributeSimportandroid。util。Limportandroid。view。MotionEimportandroid。view。Vimportandroidx。annotation。NonNimportandroidx。annotation。NpublicclassCustomVolumeProgressViewextendsView{进度条所占用的角度privatestaticfinalintARCFULLDEGREE270;绘制进度条画笔privatePaintprogressBarP绘制内心园画笔privatePaintinnerCircleP绘制小圆的画笔privatePaintsmallCircleP绘制文字的画笔privatePainttextP绘制文字大小privateinttextSize60;圆弧进度条圆心位置privateintcenterX,centerY;小圆的半径privateintsmallCircleR小圆的宽度privateintsmallCircleWidth7;圆弧进度条绘制区域privateRectFprogressBarRectF;圆弧进度值(0100)privateintmP圆弧进度最大值privateintmProgressMax100;圆弧进度条的宽度privateintprogressBarWidth8;内心园的宽度privateintinnerCircleWidth6;小圆圆心坐标floatsmallX,smallY;进度条后端的坐标floatprogressX,progressY;进度条半径floatprogressRpublicCustomVolumeProgressView(Contextcontext){super(context);init();}publicCustomVolumeProgressView(Contextcontext,NullableAttributeSetattrs){super(context,attrs);init();}publicCustomVolumeProgressView(Contextcontext,NullableAttributeSetattrs,intdefStyleAttr){super(context,attrs,defStyleAttr);init();}privatevoidinit(){初始化圆弧进度画笔progressBarPaintnewPaint();progressBarPaint。setStyle(Paint。Style。STROKE);只描边,不填充progressBarPaint。setStrokeCap(Paint。Cap。ROUND);设置圆角progressBarPaint。setAntiAlias(true);设置抗锯齿progressBarPaint。setDither(true);设置抖动progressBarPaint。setStrokeWidth(progressBarWidth);progressBarPaint。setColor(getResources()。getColor(R。color。progress));初始化跟随进度条小圆的画笔smallCirclePaintnewPaint();smallCirclePaint。setStyle(Paint。Style。FILL);填充smallCirclePaint。setStrokeCap(Paint。Cap。ROUND);设置圆角smallCirclePaint。setAntiAlias(true);设置抗锯齿smallCirclePaint。setDither(true);设置抖动smallCirclePaint。setStrokeWidth(smallCircleRadius);smallCirclePaint。setColor(getResources()。getColor(R。color。progress));初始化内心圆画笔innerCirclePaintnewPaint();innerCirclePaint。setStyle(Paint。Style。STROKE);只描边,不填充innerCirclePaint。setStrokeCap(Paint。Cap。ROUND);设置圆角innerCirclePaint。setAntiAlias(true);设置抗锯齿innerCirclePaint。setDither(true);设置抖动innerCirclePaint。setStrokeWidth(innerCircleWidth);innerCirclePaint。setColor(getResources()。getColor(R。color。innerCircle));初始化音量值画笔textPaintnewPaint();textPaint。setAntiAlias(true);textPaint。setColor(getResources()。getColor(R。color。white));textPaint。setFakeBoldText(true);textPaint。setTextSize(textSize);}OverrideprotectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec){super。onMeasure(widthMeasureSpec,heightMeasureSpec);获取圆弧进度的区域intviewWidegetMeasuredWidth()getPaddingLeft()getPaddingRight();intviewHighgetMeasuredHeight()getPaddingTop()getPaddingBottom();intmRectLength(int)((viewWideviewHigh?viewHigh:viewWide)progressBarWidth);intmRectLgetPaddingLeft()(viewWidemRectLength)2;intmRectTgetPaddingTop()(viewHighmRectLength)2;progressBarRectFnewRectF(mRectL,mRectT,mRectLmRectLength,mRectTmRectLength);获取圆弧中心坐标centerXgetMeasuredWidth()2;centerYgetMeasuredHeight()2;计算小圆到圆弧进度圆心的半径(距离)smallCircleRadiusMath。min(getMeasuredWidth(),getMeasuredHeight())2;progressRadiussmallCircleRsmallCircleRadius30;适当调整}OverrideprotectedvoidonDraw(Canvascanvas){super。onDraw(canvas);绘制进度条canvas。drawArc(progressBarRectF,90((360ARCFULLDEGREE)1),ARCFULLDEGREEmProgress100,false,progressBarPaint);绘制跟随进度条的小圆floatswipeARCFULLDEGREEmProgressmProgressMfloatradians(float)((90((360ARCFULLDEGREE)1)swipe)180Math。PI);smallXcenterXsmallCircleRadius(float)Math。cos(radians);smallYcenterYsmallCircleRadius(float)Math。sin(radians);progressXcenterXprogressRadius(float)Math。cos(radians);progressYcenterYprogressRadius(float)Math。sin(radians);canvas。drawCircle(smallX,smallY,smallCircleWidth,smallCirclePaint);绘制内心圆canvas。drawCircle(centerX,centerY,smallCircleRadius14,innerCirclePaint);绘制文字floattextWidthtextPaint。measureText(mProgress);inttextHeight(int)(Math。ceil(textPaint。getFontMetrics()。descenttextPaint。getFontMetrics()。ascent)2);canvas。drawText(mProgress,centerXtextWidth2,centerXtextHeight4,textPaint);}privatebooleanisDOverridepublicbooleanonTouchEvent(NonNullMotionEventevent){处理拖动事件floatcurrentXevent。getX();floatcurrentYevent。getY();intactionevent。getAction();switch(action){caseMotionEvent。ACTIONDOWN:判断是否在进度条thumb位置if(checkOnArc(currentX,currentY)){intnewProgress(int)(calDegreeByPosition(currentX,currentY)ARCFULLDEGREEmProgressMax);setProgressSync(newProgress);isD}caseMotionEvent。ACTIONMOVE:if(isDragging){判断拖动时是否移出去了if(checkOnArc(currentX,currentY)){setProgressSync((int)(calDegreeByPosition(currentX,currentY)ARCFULLDEGREEmProgressMax));}else{isD}}caseMotionEvent。ACTIONUP:isD}}判断该点是否在弧线上(附近)privatebooleancheckOnArc(floatcurrentX,floatcurrentY){floatdistancecalDistance(currentX,currentY,centerX,centerY);floatdegreecalDegreeByPosition(currentX,currentY);returndistanceprogressRadiusprogressBarWidth4distanceprogressRadiusprogressBarWidth4(degree30degreeARCFULLDEGREE30);}privatefloatcalDistance(floatx1,floaty1,floatx2,floaty2){return(float)Math。sqrt((x1x2)(x1x2)(y1y2)(y1y2));}根据当前位置,计算出进度条已经转过的角度。privatefloatcalDegreeByPosition(floatcurrentX,floatcurrentY){floata1(float)(Math。atan(1。0f(centerXcurrentX)(currentYcenterY))Math。PI180);if(currentYcenterY){a1180;}elseif(currentYcenterYcurrentXcenterX){a1360;}returna1(360ARCFULLDEGREE)2;}publicvoidsetProgressSync(intprogress){mProgresscheckProgress(progress);volumeProgressInterface。updatVolumeProgress(progress);invalidate();}privateVolumeProgressInterfacevolumeProgressIpublicvoidsetVolumeProgressInterface(VolumeProgressInterfacevolumeProgressInterface){this。volumeProgressInterfacevolumeProgressI}保证progress的值位于〔0,max〕privateintcheckProgress(intprogress){if(progress0){return0;}returnprogressmProgressMax?mProgressMax:}publicinterfaceVolumeProgressInterface{更新音量调节进度voidupdatVolumeProgress(intindex);}} Layout布局如下:?xmlversion1。0encodingutf8?LinearLayoutxmlns:androidhttp:schemas。android。comapkresandroidandroid:layoutwidthmatchparentandroid:layoutheightmatchparentandroid:orientationverticalandroid:gravitycenterandroid:ididlyvolumemainandroid:backgroundcolorblackRelativeLayoutandroid:ididrlvolumeandroid:layoutwidth250dpandroid:layoutheight250dpCustomVolumeProgressViewandroid:ididvolumeprogressandroid:layoutcenterHorizontaltrueandroid:layoutcenterVerticaltrueandroid:layoutwidth200dpandroid:layoutheight200dpRelativeLayoutLinearLayout MainActivity的主要操作如下:CustomVolumeProgressViewcustomVolumeProgressViewfindViewById(R。id。volumeprogress);customVolumeProgressView。setProgressSync(66);