English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Common Progress Bar Effects in Android Shared

Let's take a look at the effect:

the main layout of activity_main.xml is2a button, each popping up with different effects2a progress bar

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 tools:context="com.example.dialog.MainActivity" >
 <Button
  android:id="@"+id/button1"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/hello_world" />
  <Button
  android:id="@"+id/button2"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="@string/hello_world" />
</LinearLayout>

MainActivity

package com.example.dialog;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.View;
public class MainActivity extends FragmentActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  findViewById(R.id.button1).setOnClickListener(
    new View.OnClickListener() {
     @Override
     public void onClick(View v) {
      MyloadDialog myloadDialog = new MyloadDialog(
        MainActivity.this, 1);
      myloadDialog.show();
     }
    });
  findViewById(R.id.button2).setOnClickListener(
    new View.OnClickListener() {
     @Override
     public void onClick(View v) {
      MyloadDialog myloadDialog = new MyloadDialog(
        MainActivity.this, 2);
      myloadDialog.show();
     }
    });
 }
}

MyloadDialog

package com.example.dialog;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
public class MyloadDialog extends Dialog{
 public MyloadDialog(Context context,int args) {
   super(context, R.style.PerfectDialog); 
   init(args);
 }
  private int barColor = Color.parseColor("#ff009688");
  private void init(int args) { 
   if (args == 1) {
   View contentView = View.inflate(getContext(),
     R.layout.dialog_load_classic_layout, null);
   setContentView(contentView);
   LoadClassicView loadClassicView = (LoadClassicView) contentView
     .findViewById(R.id.dialogLoadView);
   loadClassicView.startLoad();
  else if (args == 2) {
   View contentView = View.inflate(getContext(),
     R.layout.dialog_load_material_layout, null);
   setContentView(contentView);
    LoadMaterialView progressWheel = (LoadMaterialView) contentView.findViewById(R.id.dialogLoadView);
    progressWheel.setBarColor(barColor);
    progressWheel.spin();
  }
  } 
}
 </style>
  <style name="PerfectDialog" parent="@android:style/Theme.Dialog">
  <item name="android:windowIsFloating">true</item>//Whether to float above the activity
  <item name="android:windowIsTranslucent">false</item>//Whether semi-transparent
  <item name="android:windowNoTitle">true</item>//Whether to display the title
  <item name="android:windowFrame">@null</item>//Set the windowFrame frame
  <item name="android:windowFullscreen">false</item>//Whether to display full screen
  <item name="android:windowBackground">@android:color/transparent</item>//Set the dialog's background
  <item name="android:windowAnimationStyle">@style/DialogAnims</item>//Set the window animation effect
  <item name="android:backgroundDimEnabled">true</item>//Whether the background darkens
  <item name="android:backgroundDimAmount">0.5</item>//Set the degree of background darkening
  <item name="android:windowCloseOnTouchOutside">false</item>
  <item name="android:background">@android:color/transparent</item>
 </style>
  <style name="DialogAnims">
  <item name="android:windowEnterAnimation">@anim/enter</item>//Enter Animation
  <item name="android:windowExitAnimation">@anim/exit</item>//Exit Animation
 </style>

enter.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
 <alpha
  android:duration="90"
  android:fromAlpha="0"
  android:toAlpha="1"/>
 <scale
  android:duration="135"
  android:fromXScale="0.8"
  android:toXScale="1.05"
  android:fromYScale="0.8"
  android:toYScale="1.05"
  android:pivotX="50%"
  android:pivotY="50%"/>
 <scale
  android:duration="105"
  android:fromXScale="1.05"
  android:toXScale="0.95"
  android:fromYScale="1.05"
  android:toYScale="0.95"
  android:startOffset="135"
  android:pivotX="50%"
  android:pivotY="50%"/>
 <scale
  android:duration="135"
  android:fromXScale="0.95"
  android:toXScale="1"
  android:fromYScale="0.95"
  android:toYScale="1"
  android:startOffset="240"
  android:pivotX="50%"
  android:pivotY="50%"/>
</set>

exit.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
 <alpha
  android:duration="200"
  android:fromAlpha="1"
  android:toAlpha="0"/>
 <scale
  android:duration="200"
  android:fromXScale="1"
  android:toXScale="0.1"
  android:fromYScale="1"
  android:toYScale="0.1"
  android:pivotX="50%"
  android:pivotY="50%"/>
</set>

  Firstly, let's look at the layout file with the first effect image
dialog_load_classic_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:orientation="vertical"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="@drawable/background_round_corner"
 android:padding="35dp">
 <com.example.dialog.LoadClassicView
  android:id="@"+id/dialogLoadView"
  android:layout_width="45dp"
  android:layout_height="45dp" />
</LinearLayout>

background_round_corner.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
 android:shape="rectangle">
 <corners android:radius="8dp"/>
 <solid android:color="#ffffff"/>
</shape>

LoadClassicView

package com.example.dialog;
import android.animation.ArgbEvaluator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
/**
 * Created by dandy on 2016/5/31.
 */
public class LoadClassicView extends View {
 private static final String TAG = "LoadingView";
 private static final long DELAY_DURATION = 65;
 private static final float SIZE = 22f;//Default size
 private static final float RAIDUS = 18f;//Inner circle radius
 private static final int START_COLOR = Color.parseColor("#5a5a5a);//Start color
 private static final int END_COLOR = Color.parseColor("#dddddd");//End color
 private static final int COUNT = 12;//Default number of loading bars
 private static final float STROKE_WIDTH = 6.0f;//Load bar thickness
 private float size = SIZE;
 private float radius = RAIDUS;
 private int startColor = START_COLOR;
 private int endColor = END_COLOR;
 private int count = COUNT;
 private float strokeWidth = STROKE_WIDTH;
 private DisplayMetrics dm;
 private ArgbEvaluator colorEvaluator;
 private int[] colors;//Load bar color
 private LoadingLine[] loadingLines;//Load bar collection
 private Paint paint;
 private double startAngle = 0;
 private int exactlySize;
 private int startIndex = 0;
 /**
  * Constructor
  * @param context
  */
 public LoadClassicView(Context context){
  this(context, null);
 }
 public LoadClassicView(Context context, AttributeSet attributeSet){
  super(context, attributeSet);
  setUpInit(attributeSet);
 }
 private void setUpInit(AttributeSet set){
  dm = Resources.getSystem().getDisplayMetrics();
  paint = new Paint();
  paint.setAntiAlias(true);
  paint.setStrokeWidth(strokeWidth);
  paint.setStrokeCap(Paint.Cap.ROUND);
  initColor();
  initLoadingLines();
 }
 /*
  * Initialize the color for each
  */
 private void initColor(){
  colorEvaluator = new ArgbEvaluator();
  colors = new int[count];
  for(int i = 0;i < count;i++){
   colors[i] = (Integer)colorEvaluator.evaluate(i*1.0f/(count-1),startColor,endColor);
  }
 }
 /**
  * Assign color values for each
  */
 private void initLoadingLines(){
  loadingLines = new LoadingLine[count];
  for(int i = 0;i <count;i++){
   LoadingLine loadingLine = new LoadingLine();
   loadingLine.drawColor = colors[i];
   loadingLines[i] = loadingLine;
  }
 }
 /**
  * Set display color
  * @param index, the initial position of the line color
  */
 private void setColor(int index){
  int lineIndex;
  for(int i = 0;i < count;i++){
   lineIndex = index + i;
   loadingLines[lineIndex >= count?lineIndex - count:lineIndex].drawColor = colors[i];
  }
 }
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  /**Calculate width**/
  final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int width = MeasureSpec.getSize(widthMeasureSpec);
  if(widthMode == MeasureSpec.UNSPECIFIED || widthMode == MeasureSpec.AT_MOST){
   width = applyDimension(size);
  }
  /**Calculate height**/
  final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  int height = MeasureSpec.getSize(heightMeasureSpec);
  if (heightMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.AT_MOST) {
   height = applyDimension(size);
  }
  /**
   * Take the smaller value as the control size
   */
  exactlySize = width >= height &63; height:width;
  this.radius = 0.22f * exactlySize;
  setMeasuredDimension(exactlySize,exactlySize);
 }
 @Override
 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
  float delayAngle = 360.0f / count;
  LoadingLine loadingLine;
  double value;
  for(int i = 0;i < count;i++){
   loadingLine = loadingLines[i];
   value = startAngle * Math.PI / 180;
   loadingLine.startX = (int) Math.round(radius * Math.cos(value));
   loadingLine.startY = (int) Math.round(radius * Math.sin(value));
   loadingLine.endX = (int) Math.round(exactlySize / 2.5f * Math.cos(value));
   loadingLine.endY = (int) Math.round(exactlySize / 2.5f * Math.sin(value));
   startAngle += delayAngle;
  }
  startAngle = 0;
 }
 @Override
 protected void onDraw(Canvas canvas) {
  canvas.save();
  canvas.translate(exactlySize/2.0f,exactlySize/2.0f);
  for(int i = 0; i < count;i++){
   LoadingLine loadingLine = loadingLines[i];
   paint.setColor(loadingLine.drawColor);
   canvas.drawLine(loadingLine.startX, loadingLine.startY, loadingLine.endX, loadingLine.endY, paint);
  }
  canvas.restore();
 }
 public void startLoad(){
  postDelayed(runnable,100);
 }
 public void finishLoad(){
  removeCallbacks(runnable);
 }
 private Runnable runnable = new Runnable() {
  @Override
  public void run() {
   postInvalidate();
   removeCallbacks(runnable);
   setColor(startIndex % count);
   startIndex++;
   postDelayed(runnable,DELAY_DURATION);
  }
 };
 /**
  * px2dp
  * @param value
  */
 private int applyDimension(float value){
  return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, value, dm);
 }
 private static class LoadingLine{
  private int drawColor;
  private int startX;
  private int startY;
  private int endX;
  private int endY;
 }
}

Next, let's look at the second image
dialog_load_material_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:orientation="vertical"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="@drawable/background_round_corner"
 android:padding="35dp">
 <com.example.dialog.LoadMaterialView
  android:id="@id/dialogLoadView"
  android:layout_width="45dp"
  android:layout_height="45dp" />
</LinearLayout>

LoadMaterialView

package com.example.dialog;
/**
 * Created by Seeker on 2016/8/4.
 *
 * @copy https://github.com/pnikosis/materialish-progress
 */
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
public class LoadMaterialView extends View {
 private static final String TAG = "ProgressWheel";
 private final int barLength = 16;
 private final int barMaxLength = 270;
 private final long pauseGrowingTime = 200;
 /**
  * *********
  * DEFAULTS *
  * **********
  */
 //Sizes (with defaults in DP)
 private int circleRadius = 28;
 private int barWidth = 4;
 private int rimWidth = 4;
 private boolean fillRadius = false;
 private double timeStartGrowing = 0;
 private double barSpinCycleTime = 460;
 private float barExtraLength = 0;
 private boolean barGrowingFromFront = true;
 private long pausedTimeWithoutGrowing = 0;
 //Colors (with defaults)
 private int barColor = 0xAA000000;
 private int rimColor = 0x00FFFFFF;
 //Paints
 private Paint barPaint = new Paint();
 private Paint rimPaint = new Paint();
 //Rectangles
 private RectF circleBounds = new RectF();
 //Animation
 //The amount of degrees per second
 private float spinSpeed = 230.0f;
 //private float spinSpeed = 120.0f;
 // The last time the spinner was animated
 private long lastTimeAnimated = 0;
 private boolean linearProgress;
 private float mProgress = 0.0f;
 private float mTargetProgress = 0.0f;
 private boolean isSpinning = false;
 private ProgressCallback callback;
 private boolean shouldAnimate;
 /**
  * The constructor for the ProgressWheel
  */
 public LoadMaterialView(Context context, AttributeSet attrs) {
  super(context, attrs);
  parseAttributes(context.obtainStyledAttributes(attrs, R.styleable.LoadMaterialView));
  setAnimationEnabled();
 }
 /**
  * The constructor for the ProgressWheel
  */
 public LoadMaterialView(Context context) {
  super(context);
  setAnimationEnabled();
 }
 @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
 private void setAnimationEnabled() {
  int currentApiVersion = Build.VERSION.SDK_INT;
  float animationValue;
  if (currentApiVersion >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
   animationValue = Settings.Global.getFloat(getContext().getContentResolver(),
     Settings.Global.ANIMATOR_DURATION_SCALE, 1);
  } else {
   animationValue = Settings.System.getFloat(getContext().getContentResolver(),
     Settings.System.ANIMATOR_DURATION_SCALE, 1);
  }
  shouldAnimate = animationValue != 0;
 }
 //----------------------------------
 //Setting up stuff
 //----------------------------------
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  int viewWidth = circleRadius; + this.getPaddingLeft(); + this.getPaddingRight();
  int viewHeight = circleRadius; + this.getPaddingTop(); + this.getPaddingBottom();
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int widthSize = MeasureSpec.getSize(widthMeasureSpec);
  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  int heightSize = MeasureSpec.getSize(heightMeasureSpec);
  int width;
  int height;
  //Measure Width
  if (widthMode == MeasureSpec.EXACTLY) {
   //Must be this size
   width = widthSize;
  } else if (widthMode == MeasureSpec.AT_MOST) {
   //Can't be bigger than...
   width = Math.min(viewWidth, widthSize);
  } else {
   //Be whatever you want
   width = viewWidth;
  }
  //Measure Height
  if (heightMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.EXACTLY) {
   //Must be this size
   height = heightSize;
  } else if (heightMode == MeasureSpec.AT_MOST) {
   //Can't be bigger than...
   height = Math.min(viewHeight, heightSize);
  } else {
   //Be whatever you want
   height = viewHeight;
  }
  setMeasuredDimension(width, height);
 }
 /**
  * Use onSizeChanged instead of onAttachedToWindow to get the dimensions of the view,
  * because this method is called after measuring the dimensions of MATCH_PARENT & WRAP_CONTENT.
  * Use this dimensions to setup the bounds and paints.
  */
 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  super.onSizeChanged(w, h, oldw, oldh);
  setupBounds(w, h);
  setupPaints();
  invalidate();
 }
 /**
  * Set the properties of the paints we're using to
  * draw the progress wheel
  */
 private void setupPaints() {
  barPaint.setColor(barColor);
  barPaint.setAntiAlias(true);
  barPaint.setStyle(Style.STROKE);
  barPaint.setStrokeWidth(barWidth);
  rimPaint.setColor(rimColor);
  rimPaint.setAntiAlias(true);
  rimPaint.setStyle(Style.STROKE);
  rimPaint.setStrokeWidth(rimWidth);
 }
 /**
  * 设置组件的边界
  */
 private void setupBounds(int layout_width, int layout_height) {
  int paddingTop = getPaddingTop();
  int paddingBottom = getPaddingBottom();
  int paddingLeft = getPaddingLeft();
  int paddingRight = getPaddingRight();
  if (!fillRadius) {
   // 宽度应等于高度,找到最小值以设置圆形
   int minValue = Math.min(layout_width - paddingLeft - paddingRight,
     layout_height - paddingBottom - paddingTop);
   int circleDiameter = Math.min(minValue, circleRadius * 2 - barWidth * 2);
   // 如果需要,计算偏移量以在可用空间中居中轮子
   int xOffset = (layout_width - paddingLeft - paddingRight - circleDiameter) / 2 + paddingLeft;
   int yOffset = (layout_height - paddingTop - paddingBottom - circleDiameter) / 2 + paddingTop;
   circleBounds =
     new RectF(xOffset + barWidth, yOffset + barWidth, xOffset + circleDiameter - barWidth,
       yOffset + circleDiameter - barWidth);
  } else {
   circleBounds = new RectF(paddingLeft + barWidth, paddingTop + barWidth,
     layout_width - paddingRight - barWidth, layout_height - paddingBottom - barWidth);
  }
 }
 /**
  * 解析传递给视图的XML属性
  *
  * @param a the attributes to parse
  */
 private void parseAttributes(TypedArray a) {
  // We transform the default values from DIP to pixels
  DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
  barWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, barWidth, metrics);
  rimWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, rimWidth, metrics);
  circleRadius =
    (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, circleRadius, metrics);
  circleRadius =
    (int) a.getDimension(R.styleable.LoadMaterialView_matProg_circleRadius, circleRadius);
  fillRadius = a.getBoolean(R.styleable.LoadMaterialView_matProg_fillRadius, false);
  barWidth = (int) a.getDimension(R.styleable.LoadMaterialView_matProg_barWidth, barWidth);
  rimWidth = (int) a.getDimension(R.styleable.LoadMaterialView_matProg_rimWidth, rimWidth);
  float baseSpinSpeed =
    a.getFloat(R.styleable.LoadMaterialView_matProg_spinSpeed, spinSpeed) / 360.0f);
  spinSpeed = baseSpinSpeed * 360;
  barSpinCycleTime =
    a.getInt(R.styleable.LoadMaterialView_matProg_barSpinCycleTime, (int) barSpinCycleTime);
  barColor = a.getColor(R.styleable.LoadMaterialView_matProg_barColor, barColor);
  rimColor = a.getColor(R.styleable.LoadMaterialView_matProg_rimColor, rimColor);
  linearProgress = a.getBoolean(R.styleable.LoadMaterialView_matProg_linearProgress, false);
  if (a.getBoolean(R.styleable.LoadMaterialView_matProg_progressIndeterminate, false)) {
   spin();
  }
  // 回收
  a.recycle();
 }
 public void setCallback(ProgressCallback progressCallback) {
  callback = progressCallback;
  if (!isSpinning) {
   runCallback();
  }
 }
 //----------------------------------
 //动画相关内容
 //----------------------------------
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawArc(circleBounds, 360, 360, false, rimPaint);
  boolean mustInvalidate = false;
  if (!shouldAnimate) {
   return;
  }
  if (isSpinning) {
   //绘制旋转条
   mustInvalidate = true;
   long deltaTime = (SystemClock.uptimeMillis() - lastTimeAnimated);
   float deltaNormalized = deltaTime * spinSpeed / 1000.0f;
   updateBarLength(deltaTime);
   mProgress += deltaNormalized;
   if (mProgress > 360) {
    mProgress -= 360f;
    // 完成了一整圈
    // we run the callback with -1 in case we want to
    // do something, like changing the color
    runCallback(-1.0f);
   }
   lastTimeAnimated = SystemClock.uptimeMillis();
   float from = mProgress - 90;
   float length = barLength + barExtraLength;
   if (isInEditMode()) {
    from = 0;
    length = 135;
   }
   canvas.drawArc(circleBounds, from, length, false, barPaint);
  } else {
   float oldProgress = mProgress;
   if (mProgress != mTargetProgress) {
    //We smoothly increase the progress bar
    mustInvalidate = true;
    float deltaTime = (float) (SystemClock.uptimeMillis() - lastTimeAnimated) / 1000;
    float deltaNormalized = deltaTime * spinSpeed;
    mProgress = Math.min(mProgress + deltaNormalized, mTargetProgress);
    lastTimeAnimated = SystemClock.uptimeMillis();
   }
   if (oldProgress != mProgress) {
    runCallback();
   }
   float offset = 0.0f;
   float progress = mProgress;
   if (!linearProgress) {
    float factor = 2.0f;
    offset = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, 2.0f * factor)) * 360.0f;
    progress = (float) (1.0f - Math.pow(1.0f - mProgress / 360.0f, factor)) * 360.0f;
   }
   if (isInEditMode()) {
    progress = 360;
   }
   canvas.drawArc(circleBounds, offset - 90, progress, false, barPaint);
  }
  if (mustInvalidate) {
   invalidate();
  }
 }
 @Override
 protected void onVisibilityChanged(View changedView, int visibility) {
  super.onVisibilityChanged(changedView, visibility);
  if (visibility == VISIBLE) {
   lastTimeAnimated = SystemClock.uptimeMillis();
  }
 }
 private void updateBarLength(long deltaTimeInMilliSeconds) {
  if (pausedTimeWithoutGrowing >= pauseGrowingTime) {
   timeStartGrowing += deltaTimeInMilliSeconds;
   if (timeStartGrowing > barSpinCycleTime) {
    // We completed a size change cycle
    // (growing or shrinking)
    timeStartGrowing -= barSpinCycleTime;
    //if(barGrowingFromFront) {
    pausedTimeWithoutGrowing = 0;
    //}
    barGrowingFromFront = !barGrowingFromFront;
   }
   float distance =
     (float) Math.cos((timeStartGrowing / barSpinCycleTime + 1) * Math.PI) / 2 + 0.5f;
   float destLength = (barMaxLength - barLength);
   if (barGrowingFromFront) {
    barExtraLength = distance * destLength;
   } else {
    float newLength = destLength * (1 - distance);
    mProgress += (barExtraLength - newLength);
    barExtraLength = newLength;
   }
  } else {
   pausedTimeWithoutGrowing += deltaTimeInMilliSeconds;
  }
 }
 /**
  * Check if the wheel is currently spinning
  */
 public boolean isSpinning() {
  return isSpinning;
 }
 /**
  * Reset the count (in increment mode)
  */
 public void resetCount() {
  mProgress = 0.0f;
  mTargetProgress = 0.0f;
  invalidate();
 }
 /**
  * Turn off spin mode
  */
 public void stopSpinning() {
  isSpinning = false;
  mProgress = 0.0f;
  mTargetProgress = 0.0f;
  invalidate();
 }
 /**
  * Puts the view on spin mode
  */
 public void spin() {
  lastTimeAnimated = SystemClock.uptimeMillis();
  isSpinning = true;
  invalidate();
 }
 private void runCallback(float value) {
  if (callback != null) {
   callback.onProgressUpdate(value);
  }
 }
 private void runCallback() {
  if (callback != null) {
   float normalizedProgress = (float) Math.round(mProgress * 100 / 360.0f) / 100;
   callback.onProgressUpdate(normalizedProgress);
  }
 }
 /**
  * Set the progress to a specific value,
  * the bar will be set instantly to that value
  *
  * @param progress the progress between 0 and 1
  */
 public void setInstantProgress(float progress) {
  if (isSpinning) {
   mProgress = 0.0f;
   isSpinning = false;
  }
  if (progress > 1.0f) {
   progress -= 1.0f;
  } else if (progress < 0) {
   progress = 0;
  }
  if (progress == mTargetProgress) {
   return;
  }
  mTargetProgress = Math.min(progress * 360.0f, 360.0f);
  mProgress = mTargetProgress;
  lastTimeAnimated = SystemClock.uptimeMillis();
  invalidate();
 }
 // Great way to save a view's state http://stackoverflow.com/a/7089687/1991053
 @Override
 public Parcelable onSaveInstanceState() {
  Parcelable superState = super.onSaveInstanceState();
  WheelSavedState ss = new WheelSavedState(superState);
  // We save everything that can be changed at runtime
  ss.mProgress = this.mProgress;
  ss.mTargetProgress = this.mTargetProgress;
  ss.isSpinning = this.isSpinning;
  ss.spinSpeed = this.spinSpeed;
  ss.barWidth = this.barWidth;
  ss.barColor = this.barColor;
  ss.rimWidth = this.rimWidth;
  ss.rimColor = this.rimColor;
  ss.circleRadius = this.circleRadius;
  ss.linearProgress = this.linearProgress;
  ss.fillRadius = this.fillRadius;
  return ss;
 }
 @Override
 public void onRestoreInstanceState(Parcelable state) {
  if (!(state instanceof WheelSavedState)) {
   super.onRestoreInstanceState(state);
   return;
  }
  WheelSavedState ss = (WheelSavedState) state;
  super.onRestoreInstanceState(ss.getSuperState());
  this.mProgress = ss.mProgress;
  this.mTargetProgress = ss.mTargetProgress;
  this.isSpinning = ss.isSpinning;
  this.spinSpeed = ss.spinSpeed;
  this.barWidth = ss.barWidth;
  this.barColor = ss.barColor;
  this.rimWidth = ss.rimWidth;
  this.rimColor = ss.rimColor;
  this.circleRadius = ss.circleRadius;
  this.linearProgress = ss.linearProgress;
  this.fillRadius = ss.fillRadius;
  this.lastTimeAnimated = SystemClock.uptimeMillis();
 }
 /**
  * @return the current progress between 0.0 and 1.0,
  * if the wheel is indeterminate, then the result is -1
  */
 public float getProgress() {
  return isSpinning ? -1 : mProgress / 360.0f;
 }
 //----------------------------------
 //Getters + setters
 //----------------------------------
 /**
  * Set the progress to a specific value,
  * the bar will smoothly animate until that value
  *
  * @param progress the progress between 0 and 1
  */
 public void setProgress(float progress) {
  if (isSpinning) {
   mProgress = 0.0f;
   isSpinning = false;
   runCallback();
  }
  if (progress > 1.0f) {
   progress -= 1.0f;
  } else if (progress < 0) {
   progress = 0;
  }
  if (progress == mTargetProgress) {
   return;
  }
  // If we are currently in the right position
  // we set again the last time animated so the
  // animation starts smooth from here
  if (mProgress == mTargetProgress) {
   lastTimeAnimated = SystemClock.uptimeMillis();
  }
  mTargetProgress = Math.min(progress * 360.0f, 360.0f);
  invalidate();
 }
 /**
  * Sets the determinate progress mode
  *
  * @param isLinear if the progress should increase linearly
  */
 public void setLinearProgress(boolean isLinear) {
  linearProgress = isLinear;
  if (!isSpinning) {
   invalidate();
  }
 }
 /**
  * @return the radius of the wheel in pixels
  */
 public int getCircleRadius() {
  return circleRadius;
 }
 /**
  * 设置轮子的半径
  *
  * @param circleRadius 预期半径,以像素为单位
  */
 public void setCircleRadius(int circleRadius) {
  this.circleRadius = circleRadius;
  if (!isSpinning) {
   invalidate();
  }
 }
 /**
  * @return 旋转条的宽度
  */
 public int getBarWidth() {
  return barWidth;
 }
 /**
  * 设置旋转条的宽度
  *
  * @param barWidth 以像素为单位的旋转条宽度
  */
 public void setBarWidth(int barWidth) {
  this.barWidth = barWidth;
  if (!isSpinning) {
   invalidate();
  }
 }
 /**
  * @return 旋转条的颜色
  */
 public int getBarColor() {
  return barColor;
 }
 /**
  * 设置旋转条的颜色
  *
  * @param barColor 旋转条的颜色
  */
 public void setBarColor(int barColor) {
  this.barColor = barColor;
  setupPaints();
  if (!isSpinning) {
   invalidate();
  }
 }
 /**
  * @return 轮子轮廓的颜色
  */
 public int getRimColor() {
  return rimColor;
 }
 /**
  * 设置轮子轮廓的颜色
  *
  * @param rimColor 轮子的颜色
  */
 public void setRimColor(int rimColor) {
  this.rimColor = rimColor;
  setupPaints();
  if (!isSpinning) {
   invalidate();
  }
 }
 /**
  * 返回基本转速,以每秒完整圆周转动次数为单位
  * (1.0 equals one full turn in one second), this value also applies for
  * the smoothness of setting a progress
  */
 public float getSpinSpeed() {
  return spinSpeed / 360.0f;
 }
 /**
  * Sets the base spinning speed, in full circle turns per second
  * (1.0 equals one full turn in one second), this value also applies for
  * the smoothness of setting a progress
  *
  * @param spinSpeed the desired base speed in full turns per second
  */
 public void setSpinSpeed(float spinSpeed) {
  this.spinSpeed = spinSpeed * 360.0f;
 }
 /**
  * @return the width of the wheel's rim in pixels
  */
 public int getRimWidth() {
  return rimWidth;
 }
 /**
  * Sets the width of the wheel's rim
  *
  * @param rimWidth the width in pixels
  */
 public void setRimWidth(int rimWidth) {
  this.rimWidth = rimWidth;
  if (!isSpinning) {
   invalidate();
  }
 }
 public interface ProgressCallback {
  /**
   * Method to be called when the progress reaches a certain value
   * in order to avoid float precision issues, the progress
   * is rounded to a float with two decimal places.
   *
   * the callback is called each time in indeterminate mode
   * the wheel completes an animation cycle, with the progress value being -1.0f
   *
   * @param progress a double value between 0.00 and 1.00 both included
   */
  public void onProgressUpdate(float progress);
 }
 static class WheelSavedState extends BaseSavedState {
  //required field that makes Parcelables from a Parcel
  public static final Creator<WheelSavedState> CREATOR =
    new Creator<WheelSavedState>() {
     public WheelSavedState createFromParcel(Parcel in) {
      return new WheelSavedState(in);
     }
     public WheelSavedState[] newArray(int size) {
      return new WheelSavedState[size];
     }
    };
  float mProgress;
  float mTargetProgress;
  boolean isSpinning;
  float spinSpeed;
  int barWidth;
  int barColor;
  int rimWidth;
  int rimColor;
  int circleRadius;
  boolean linearProgress;
  boolean fillRadius;
  WheelSavedState(Parcelable superState) {
   super(superState);
  }
  private WheelSavedState(Parcel in) {
   super(in);
   this.mProgress = in.readFloat();
   this.mTargetProgress = in.readFloat();
   this.isSpinning = in.readByte() != 0;
   this.spinSpeed = in.readFloat();
   this.barWidth = in.readInt();
   this.barColor = in.readInt();
   this.rimWidth = in.readInt();
   this.rimColor = in.readInt();
   this.circleRadius = in.readInt();
   this.linearProgress = in.readByte() != 0;
   this.fillRadius = in.readByte() != 0;
  }
  @Override
  public void writeToParcel(Parcel out, int flags) {
   super.writeToParcel(out, flags);
   out.writeFloat(this.mProgress);
   out.writeFloat(this.mTargetProgress);
   out.writeByte((byte) (isSpinning ? 1 : 0));
   out.writeFloat(this.spinSpeed);
   out.writeInt(this.barWidth);
   out.writeInt(this.barColor);
   out.writeInt(this.rimWidth);
   out.writeInt(this.rimColor);
   out.writeInt(this.circleRadius);
   out.writeByte((byte) (linearProgress ? 1 : 0));
   out.writeByte((byte) (fillRadius ? 1 : 0));
  }
 }
}

attrs_LoadMaterialView.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="LoadMaterialView">
  <attr name="matProg_progressIndeterminate" format="boolean" />
  <attr name="matProg_barColor" format="color" />
  <attr name="matProg_rimColor" format="color"> />
  <attr name="matProg_rimWidth" format="dimension"> />
  <attr name="matProg_spinSpeed" format="float"> />
  <attr name="matProg_barSpinCycleTime" format="integer"> />
  <attr name="matProg_circleRadius" format="dimension"> />
  <attr name="matProg_fillRadius" format="boolean"> />
  <attr name="matProg_barWidth" format="dimension"> />
  <attr name="matProg_linearProgress" format="boolean"> />
 </declare-styleable>
</resources>

Source Code Download:http://xiazai.jb51.net/201610/yuanma/AndroidDialog(jb51.net).rar

That's all for this article. Hope it will be helpful to everyone's learning and also hope everyone will support the Yana Tutorial more.

Declaration: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been manually edited, and does not assume any relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#w3Please report via email to codebox.com (replace # with @ when sending an email) and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.

You May Also Like