編輯:關於Android編程
啦啦啦,今天給大家帶來最近弄的CircleProgress相關的效果。這裡的效果圖可能還看不出是UC浏覽器的那個下拉刷新的效果,不過首先還是要說說這個進度條,在下一篇中將實現真正的下拉刷新!
話不多說,直接上圖:
seo=" src="/uploadfile/Collfiles/20160809/201608090936031694.gif" title="\" />
特點:就是一個進度條
1、可以設置多種顏色。
2、可以顯示多種狀態(LOADING、SUCCESS、ERROR,其實遠不止這幾種)
3、可以控制是否顯示箭頭
相關准備工作
知識點:
1.
Canvas裡面相關方法
2.drawArc()畫圓弧的方法
3.drawPath()畫路徑的方法
4.屬性動畫使用
結果的鉤鉤或者那個叉叉還有那個箭頭都是使用
drawPath()來完成的。
在onDraw裡面對應有四個相關的方法:
1.
drawArc(Canvas canvas):畫對應的進度
2.drawTriangle(Canvas c, float startAngle, float sweepAngle):畫箭頭
3.drawHook(Canvas canvas):畫鉤鉤
4.drawError(Canvas canvas):畫叉叉
三個動畫控制:
兩個來控制進度條的
startAngle和
sweepAngle,一個用來控制畫鉤鉤或者畫叉叉的時候的漸變效果!
相關代碼
三支畫筆
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Cap.ROUND);
mPaint.setStrokeWidth(mBorderWidth);
mPaint.setColor(mColors[mCurrentColorIndex]);
mHookPaint = new Paint(mPaint);
mArrowPaint = new Paint(mPaint);
三個動畫
private void setupAnimations() {
mObjectAnimatorAngle = ObjectAnimator.ofFloat(this, mAngleProperty, 360f);
mObjectAnimatorAngle.setInterpolator(ANGLE_INTERPOLATOR);
mObjectAnimatorAngle.setDuration(ANGLE_ANIMATOR_DURATION);
mObjectAnimatorAngle.setRepeatMode(ValueAnimator.RESTART);
mObjectAnimatorAngle.setRepeatCount(ValueAnimator.INFINITE);
mObjectAnimatorSweep = ObjectAnimator.ofFloat(this, mSweepProperty, 360f - MIN_SWEEP_ANGLE * 2);
mObjectAnimatorSweep.setInterpolator(SWEEP_INTERPOLATOR);
mObjectAnimatorSweep.setDuration(SWEEP_ANIMATOR_DURATION);
mObjectAnimatorSweep.setRepeatMode(ValueAnimator.RESTART);
mObjectAnimatorSweep.setRepeatCount(ValueAnimator.INFINITE);
mObjectAnimatorSweep.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationRepeat(Animator animation) {
toggleAppearingMode();
}
});
fractionAnimator = ValueAnimator.ofInt(0, 255);
fractionAnimator.setInterpolator(ANGLE_INTERPOLATOR);
fractionAnimator.setDuration(100);
fractionAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
fraction = animation.getAnimatedFraction();
mHookPaint.setAlpha((Integer) animation.getAnimatedValue());
invalidate();
}
});
}
四個draw相關方法
private void drawError(Canvas canvas) {
mError.reset();
mError.moveTo(fBounds.centerX() + fBounds.width() * 0.2f * fraction, fBounds.centerY() - fBounds.height() * 0.2f * fraction);
mError.lineTo(fBounds.centerX() - fBounds.width() * 0.2f * fraction, fBounds.centerY() + fBounds.height() * 0.2f * fraction);
mError.moveTo(fBounds.centerX() - fBounds.width() * 0.2f * fraction, fBounds.centerY() - fBounds.height() * 0.2f * fraction);
mError.lineTo(fBounds.centerX() + fBounds.width() * 0.2f * fraction, fBounds.centerY() + fBounds.height() * 0.2f * fraction);
mHookPaint.setColor(mColors[3]);
canvas.drawPath(mError, mHookPaint);
canvas.drawArc(fBounds, 0, 360, false, mHookPaint);
}
private void drawHook(Canvas canvas) {
mHook.reset();
mHook.moveTo(fBounds.centerX() - fBounds.width() * 0.25f * fraction, fBounds.centerY());
mHook.lineTo(fBounds.centerX() - fBounds.width() * 0.1f * fraction, fBounds.centerY() + fBounds.height() * 0.18f * fraction);
mHook.lineTo(fBounds.centerX() + fBounds.width() * 0.25f * fraction, fBounds.centerY() - fBounds.height() * 0.20f * fraction);
mHookPaint.setColor(mColors[0]);
canvas.drawPath(mHook, mHookPaint);
canvas.drawArc(fBounds, 0, 360, false, mHookPaint);
}
private void drawArc(Canvas canvas) {
float startAngle = mCurrentGlobalAngle - mCurrentGlobalAngleOffset;
float sweepAngle = mCurrentSweepAngle;
if (mModeAppearing) {
mPaint.setColor(gradient(mColors[mCurrentColorIndex], mColors[mNextColorIndex],
mCurrentSweepAngle / (360 - MIN_SWEEP_ANGLE * 2)));
sweepAngle += MIN_SWEEP_ANGLE;
} else {
startAngle = startAngle + sweepAngle;
sweepAngle = 360 - sweepAngle - MIN_SWEEP_ANGLE;
}
canvas.drawArc(fBounds, startAngle, sweepAngle, false, mPaint);
if (showArrow) {
drawTriangle(canvas, startAngle, sweepAngle);
}
}
public void drawTriangle(Canvas c, float startAngle, float sweepAngle) {
if (mArrow == null) {
mArrow = new Path();
mArrow.setFillType(Path.FillType.EVEN_ODD);
} else {
mArrow.reset();
}
float x = (float) (mRingCenterRadius * Math.cos(0) + fBounds.centerX());
float y = (float) (mRingCenterRadius * Math.sin(0) + fBounds.centerY());
mArrow.moveTo(0, 0);
mArrow.lineTo(ARROW_WIDTH * mArrowScale, 0);
mArrow.lineTo((ARROW_WIDTH * mArrowScale / 2), (ARROW_HEIGHT
* mArrowScale));
mArrow.offset(x, y);
mArrow.close();
c.rotate(startAngle + sweepAngle, fBounds.centerX(),
fBounds.centerY());
c.drawPath(mArrow, mPaint);
}
上面的代碼就是相關核心的方法了,其實對應的進度條效果就是控制
startAngle和
sweepAngle這兩個對應的字段,然後不斷的調用
drawArc()方法。
對於畫鉤鉤或者畫叉叉,就是一個
ValueAnimator,通過百分比控制縮放和畫筆的透明度。
對於
drawTriangle()方法,如果你覺得很眼熟的話也很正常,其實這個就是在
SwipeRefreshLayout裡面抄過來的。。。。。
一開始,我很糾結這個箭頭怎麼才能跟著進度條一起旋轉,自己寫的也是有各種問題,另外mArrowScale這個參數在裡面其實沒有使用的。
如果沒有offset偏移量,那麼那個path肯定是畫在左上角的。
x=mRingCenterRadius +fBounds.centerX();
y=fBounds.centerY();
通過這個一設置,這個path其實就到了右邊的中間靠著圓弧的內側一點去了(因為這裡的半徑減去了圓弧自己的寬度。。),這麼一來,再根據相關的角度旋轉角度,就有一種跟著進度條一直轉的效果了!
對於
drawArc()方法,主要是控制
startAngle和
sweepAngle這兩個變量,
mCurrentGlobalAngle的變化范圍是(0~360),而
mCurrentSweepAngle的變化范圍是(0~360f - MIN_SWEEP_ANGLE * 2),為什麼要減去兩個最小值呢?因為
sweepAngle總會加一個或者總會減去一個最小值,所以最小間距還是
MIN_SWEEP_ANGLE。
至於什麼時候加什麼時候減呢?這裡有一個變量值mModeAppearing提供記錄!那就是當
mObjectAnimatorSweep的動畫重復的時候,就需要切換一下了。。
mObjectAnimatorSweep.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationRepeat(Animator animation) {
toggleAppearingMode();
}
});
private void toggleAppearingMode() {
mModeAppearing = !mModeAppearing;
if (mModeAppearing) {
mCurrentColorIndex = ++mCurrentColorIndex % 4;
mNextColorIndex = ++mNextColorIndex % 4;
mCurrentGlobalAngleOffset = (mCurrentGlobalAngleOffset + MIN_SWEEP_ANGLE * 2) % 360;
}
}
最終效果圖
下一篇Android 自定義View UC下拉刷新效果(二)
介紹剩余的下拉刷新部分,還有就是兩個圓圈的過度效果。。
相關的代碼請移步 我的github。。。
— Edit By Joe —
今天在Android Studio中把另外一個項目引入當前項目,編譯的時候出現了java.util.zip.ZipException: duplicate entry錯誤
1、volley項目地址 https://github.com/smanikandan14/Volley-demo(1) JSON,圖像等的異步下載;(2) 網絡請求的排
許多項目都必須用到上傳圖片的功能,有了圖片會更加精彩,最近我的項目也需要選擇圖片的功能,所以把我寫的代碼共享出來,也算是筆記吧!好,廢話少說,下面看看效果圖: 效果還
shape_rectangle.xml shape_oval.xml shape_line.xml