實現一個Material效果的ProgressBar
先來看看效果:
分析下難點:
1. 動畫的實現;
2. 邊界的控制;
3. 狀態儲存與恢復;
4. 兩種狀態的實現,loading狀態(不停旋轉)、progress狀態。
分別來看下。
1. 動畫如何實現:
將動畫進行拆解,可以發現它其實是一個弧不斷變長變短的一個過程+弧本身在繞圓形轉動兩部分組成。
所以可以分開來處理,弧度變長變短可以通過canvas.drawArc的引數startAngle/SweeepAngle控制,只要改變這兩個值即可實現效果。怎麼改變?有幾種方案,1是通過hander+thread;2是通過View.post();3是通過PropertyAnimation.
弧本身繞圓心運動可以通過Canvas.rotate實現。
private static final float delta = 6f;
private float temp = 0;
class AnimRunnable implements Runnable{
@Override
public void run() {
if (mStartAngle == temp) {
mSweepAngle += delta;
}
if (mSweepAngle >= 280 || mStartAngle > temp) {
mStartAngle += delta;
if(mSweepAngle > 20) {
mSweepAngle -= delta;
}
}
if (mStartAngle > temp + 280) {
temp = mStartAngle;
mStartAngle = temp;
mSweepAngle = 20;
}
postInvalidate();
postDelayed(this,mSpinSpeed);
}
}
2.邊界的控制:
需要在onMeasure中控制。在onSizeChanged方法中可以拿到最終的width、height,通過width/height就可以控制progressbar的邊界了。
需要注意的是,邊界需要是正方形的,所以得考慮寬高不相等的情況以及四個方向padding的大小。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//計算自己需要的寬度和高度
int width = mCircleRadius*2;
int height = mCircleRadius*2;
//考慮父容器的測量規則
setMeasuredDimension(getResolvedSize(width, widthMeasureSpec), getResolvedSize(height, heightMeasureSpec));
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
int paddingLeft = getPaddingLeft();
int paddingTop = getPaddingTop();
int paddingRight = getPaddingRight();
int paddingBottom = getPaddingBottom();
//簡化處理,以最大的padding作為padding
int padding = Math.max(Math.max(paddingLeft, paddingRight), Math.max(paddingTop, paddingBottom));
int diameter;
//保證bounds是一個正方形
if(w >= h){
diameter = h;
mBounds = new RectF(padding+mBarWidth+(w-h)/2,padding+mBarWidth,diameter-padding-mBarWidth+(w-h)/2,diameter-padding-mBarWidth);
}else if(w < h){
diameter = w;
mBounds = new RectF(padding+mBarWidth,padding+mBarWidth+(h-w)/2,diameter-padding-mBarWidth,diameter-padding-mBarWidth+(h-w)/2);
}
}
3.狀態的儲存與恢復:
progressbar的狀態不能因為橫豎屏切換等問題丟失,所以需要通過重寫onSaveInstanceState/onRestoreInstanceState來儲存/恢復狀態.
@Override
protected void onRestoreInstanceState(Parcelable state) {
if(! (state instanceof SavedState)){
super.onRestoreInstanceState(state);
return;
}
//先恢復父類的狀態
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
//在恢復自己的狀態
this.mCurMode = savedState.mCurMode == 0 ? Mode.INDETERMINATE : Mode.DETERMINATE;
this.mRimWidth = savedState.mRimWidth;
this.mRimColor = savedState.mRimColor;
this.mBarColor = savedState.mBarColor;
this.mBarWidth = savedState.mBarWidth;
this.showRim = savedState.showRim;
this.isAnimStart = savedState.isAnimStart;
this.mProgress = savedState.mProgress;
}
@Override
protected Parcelable onSaveInstanceState() {
//相當於是做了一層包裝
//先儲存父類的狀態,然後包裝,再儲存自己的狀態
Parcelable parcelable = super.onSaveInstanceState();
SavedState savedState = new SavedState(parcelable);
savedState.mCurMode = (this.mCurMode == Mode.INDETERMINATE) ? 0 : 1;
savedState.mRimWidth = this.mRimWidth;
savedState.mRimColor = this.mRimColor;
savedState.mBarColor = this.mBarColor;
savedState.mBarWidth = this.mBarWidth;
savedState.showRim = this.showRim;
savedState.isAnimStart = this.isAnimStart;
savedState.mProgress = this.mProgress;
return savedState;
}
4.兩種狀態的實現:
自然是通過一個變數記錄當前模式,在onDraw中通過判斷模式進行不同的繪製操作。
相關文章
- 用CSS Houdini實現一個Material風格的按鈕CSS
- 實現一個煙花效果
- 使用純 CSS 實現仿 Material Design 的 input 過渡效果CSSMaterial Design
- Material Design之CollapsingToolbarLayout,實現Toolbar的摺疊效果Material Design
- 用Flutter實現一個仿Twitter的點贊效果Flutter
- 使用 Flutter 自定義一個 ProgressBar - IntervalProgressBarFlutter
- 實現給一個DIV加陰影效果!
- 如何從零實現一個詞雲效果
- 一個簡單的滾動數字的效果實現
- 使用JS實現一個簡單的選項卡效果JS
- Android技術分享|【自定義View】實現Material Design的Loading效果AndroidViewMaterial Design
- 簡單實現一個全面屏切換效果
- 如何快速實現一個無縫輪播效果
- 用Python實現一個實時運動的大掛鐘效果Python
- Flutter | 如何實現一個水波紋擴散效果的 WidgetFlutter
- 怎麼實現一個3d翻書效果3D
- viewpager實現畫廊(一屏多個Fragment)效果ViewpagerFragment
- 14個HTML5實現的效果合集HTML
- Android之利用Handler實現ProgressBar進度條Android
- [ Shell ] 兩個 case 實現 GetOptions 效果
- 強大的CSS:placeholder-shown偽類實現Material Design佔位符互動效果CSSMaterial Design
- CSS實現兩個球相交的粘粘效果CSS
- jquery如何用each遍歷實現一個排異切換的效果?jQuery
- js實現的點選一個div顯示,其他div隱藏效果JS
- 如何實現兩個div等高效果
- 如何通過 Web 技術實現一個簡單但有趣的 AR 效果Web
- 淺析實現平鋪排列多個View的效果View
- Android Material Design 陰影實現AndroidMaterial Design
- 實現畫布的效果
- 記一個angular在路由配置中管理 Angular Material Dialog(實現動態元件的彈窗顯示)Angular路由元件
- iOS開發UI篇--使用UICollectionView實現一個傾斜列表效果iOSUIView
- 使用float,flex和tailwind實現同一個表單註冊效果FlexAI
- 基於 Angular Material 的 Data Grid 設計實現Angular
- 實現Instagram的Material Design概念設計(1)Material Design
- 實現環形進度條效果【一】
- 【Android初級】如何實現一個有動畫效果的自定義下拉選單Android動畫
- iOS開發UI篇--使用UICollectionView實現一個列表頭部拉伸效果的案例iOSUIView
- Java在Swing中如何實現彈出一個對話方塊的效果?Java