首先这个工具类是由V4包提供的,翻看里面的源码发现,原来这个工具视图[主要探讨视图]是通过自己创建了一个圆形VIew,并在圆形View里面添加了一个旋转的进度Drawable,当然旋转的并不是一个控件,仅仅是一个资源.并通过圆形View去设置了该Drawable,并将圆形图片添加到了SwieRefresh控件上.具体源码如下,通过该源码你可以找到MaterialProgressDrawable,自己手动实现一些进度,大致看了一下算法,还不错,如果你想依赖原生的,你就可以自己创建一个控件去设置这个背景.
mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT, CIRCLE_DIAMETER/2); mProgress = new MaterialProgressDrawable(getContext(), this); mProgress.setBackgroundColor(CIRCLE_BG_LIGHT); mCircleView.setImageDrawable(mProgress);//设置圆形进度资源 mCircleView.setVisibility(View.GONE); addView(mCircleView);然后 MaterialProgressDrawable提供一些方便的api,
<pre name="code" class="java">setAlpha(float); // 设置渐变 showArrow(boolean);// 设置箭头 setStartEndTrim(float,float); // 开始和结束的长度这里默认是0.8f,参考源码:mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart)); setArrowScale(float); //缩放箭头
<pre name="code" class="java">float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f; // ACTION_MOVE的时候计算的一个旋转值,然后给该设置,当然你也可以自己定义. mProgress.setProgressRotation(rotation);// 设置旋转值. mProgress.start();//开始旋转 mProgress.stop(); // 结束旋转.
下面是MaterialProcessDrawable部分算法源码:
// The minProgressArc is calculated from 0 to create an // angle that // matches the stroke width. final float minProgressArc = (float) Math.toRadians( ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius())); final float startingEndTrim = ring.getStartingEndTrim(); final float startingTrim = ring.getStartingStartTrim(); final float startingRotation = ring.getStartingRotation(); // Offset the minProgressArc to where the endTrim is // located. final float minArc = MAX_PROGRESS_ARC - minProgressArc; final float endTrim = startingEndTrim + (minArc * START_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime)); ring.setEndTrim(endTrim); final float startTrim = startingTrim + (MAX_PROGRESS_ARC * END_CURVE_INTERPOLATOR.getInterpolation(interpolatedTime)); ring.setStartTrim(startTrim); final float rotation = startingRotation + (0.25f * interpolatedTime); ring.setRotation(rotation); float groupRotation = ((720.0f / NUM_POINTS) * interpolatedTime) + (720.0f * (mRotationCount / NUM_POINTS)); setRotation(groupRotation);//设置旋转值
/** *画箭头 * */ private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) { if (mShowArrow) { if (mArrow == null) { mArrow = new android.graphics.Path(); mArrow.setFillType(android.graphics.Path.FillType.EVEN_ODD); } else { mArrow.reset(); } // Adjust the position of the triangle so that it is inset as // much as the arc, but also centered on the arc. float inset = (int) mStrokeInset / 2 * mArrowScale; float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX()); float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY()); // Update the path each time. This works around an issue in SKIA // where concatenating a rotation matrix to a scale matrix // ignored a starting negative rotation. This appears to have // been fixed as of API 21. mArrow.moveTo(0, 0); mArrow.lineTo(mArrowWidth * mArrowScale, 0); mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight * mArrowScale)); mArrow.offset(x - inset, y); mArrow.close(); // draw a triangle mArrowPaint.setColor(mColors[mColorIndex]); c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(), bounds.exactCenterY()); c.drawPath(mArrow, mArrowPaint); } }
这儿主要是画进度:
/** * Draw the progress spinner */ public void draw(Canvas c, Rect bounds) { final RectF arcBounds = mTempBounds; arcBounds.set(bounds); arcBounds.inset(mStrokeInset, mStrokeInset); final float startAngle = (mStartTrim + mRotation) * 360; final float endAngle = (mEndTrim + mRotation) * 360; float sweepAngle = endAngle - startAngle; mPaint.setColor(mColors[mColorIndex]); c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint); drawTriangle(c, startAngle, sweepAngle, bounds); if (mAlpha < 255) { mCirclePaint.setColor(mBackgroundColor); mCirclePaint.setAlpha(255 - mAlpha); c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2, mCirclePaint); } }
下面是我自己定义的CircleView,算法如下.:
mRefreshStart += mIsStart ? 3 : 10;//计算距离 mRefreshStop += mIsStart ? 10 : 3; mRefreshStart = mRefreshStart % 360;//还原位置 mRefreshStop = mRefreshStop % 360; int swipe = mRefreshStop - mRefreshStart; swipe = swipe < 0 ? swipe + 360 : swipe; //计算扫过的角度. canvas.drawArc(rectF, mRefreshStart, swipe, false, mOutPaint);//画圆弧. if (swipe >= 330) {//恢复加速 mIsStart = false; } else if (swipe <= 10) {//开始加速 mIsStart = true; }