فهرست منبع

A Material indeterminate progress indicator is used below API 21 (L), and above API 14 (ICS). Resolves #534.

Aidan Follestad 10 سال پیش
والد
کامیت
405c39a4c2

+ 14 - 1
library/src/main/java/com/afollestad/materialdialogs/DialogInit.java

@@ -22,6 +22,7 @@ import android.widget.TextView;
 import com.afollestad.materialdialogs.internal.MDButton;
 import com.afollestad.materialdialogs.internal.MDRootLayout;
 import com.afollestad.materialdialogs.internal.MDTintHelper;
+import com.afollestad.materialdialogs.progress.CircularProgressDrawable;
 import com.afollestad.materialdialogs.simplelist.MaterialSimpleListAdapter;
 import com.afollestad.materialdialogs.util.DialogUtils;
 
@@ -329,7 +330,19 @@ class DialogInit {
         if (builder.indeterminateProgress || builder.progress > -2) {
             dialog.mProgress = (ProgressBar) dialog.view.findViewById(android.R.id.progress);
             if (dialog.mProgress == null) return;
-            MDTintHelper.setTint(dialog.mProgress, builder.widgetColor);
+
+            if (builder.indeterminateProgress &&
+                    Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH &&
+                    Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+                dialog.mProgress.setIndeterminateDrawable(new CircularProgressDrawable(
+                        builder.widgetColor, builder.context.getResources().getDimension(R.dimen.circular_progress_border)));
+            } else if (!builder.indeterminateProgress && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+                dialog.mProgress.setIndeterminateDrawable(new CircularProgressDrawable(
+                        builder.widgetColor, builder.context.getResources().getDimension(R.dimen.circular_progress_border)));
+                MDTintHelper.setTint(dialog.mProgress, builder.widgetColor, true);
+            } else {
+                MDTintHelper.setTint(dialog.mProgress, builder.widgetColor);
+            }
 
             if (!builder.indeterminateProgress) {
                 dialog.mProgress.setProgress(0);

+ 7 - 2
library/src/main/java/com/afollestad/materialdialogs/internal/MDTintHelper.java

@@ -66,17 +66,22 @@ public class MDTintHelper {
     }
 
     public static void setTint(ProgressBar progressBar, int color) {
+        setTint(progressBar, color, false);
+    }
+
+    public static void setTint(ProgressBar progressBar, int color, boolean skipIndeterminate) {
         ColorStateList sl = ColorStateList.valueOf(color);
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
             progressBar.setProgressTintList(sl);
             progressBar.setSecondaryProgressTintList(sl);
-            progressBar.setIndeterminateTintList(sl);
+            if (!skipIndeterminate)
+                progressBar.setIndeterminateTintList(sl);
         } else {
             PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN;
             if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
                 mode = PorterDuff.Mode.MULTIPLY;
             }
-            if (progressBar.getIndeterminateDrawable() != null)
+            if (!skipIndeterminate && progressBar.getIndeterminateDrawable() != null)
                 progressBar.getIndeterminateDrawable().setColorFilter(color, mode);
             if (progressBar.getProgressDrawable() != null)
                 progressBar.getProgressDrawable().setColorFilter(color, mode);

+ 206 - 0
library/src/main/java/com/afollestad/materialdialogs/progress/CircularProgressDrawable.java

@@ -0,0 +1,206 @@
+package com.afollestad.materialdialogs.progress;
+
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Animatable;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.util.Property;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
+
+@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+public class CircularProgressDrawable extends Drawable
+        implements Animatable {
+
+    private static final Interpolator ANGLE_INTERPOLATOR = new LinearInterpolator();
+    private static final Interpolator SWEEP_INTERPOLATOR = new DecelerateInterpolator();
+    private static final int ANGLE_ANIMATOR_DURATION = 2000;
+    private static final int SWEEP_ANIMATOR_DURATION = 600;
+    private static final int MIN_SWEEP_ANGLE = 30;
+    private final RectF fBounds = new RectF();
+
+    private ObjectAnimator mObjectAnimatorSweep;
+    private ObjectAnimator mObjectAnimatorAngle;
+    private boolean mModeAppearing;
+    private Paint mPaint;
+    private float mCurrentGlobalAngleOffset;
+    private float mCurrentGlobalAngle;
+    private float mCurrentSweepAngle;
+    private float mBorderWidth;
+    private boolean mRunning;
+
+    public CircularProgressDrawable(int color, float borderWidth) {
+        mBorderWidth = borderWidth;
+
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setStyle(Paint.Style.STROKE);
+        mPaint.setStrokeWidth(borderWidth);
+        mPaint.setColor(color);
+
+        setupAnimations();
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        float startAngle = mCurrentGlobalAngle - mCurrentGlobalAngleOffset;
+        float sweepAngle = mCurrentSweepAngle;
+        if (!mModeAppearing) {
+            startAngle = startAngle + sweepAngle;
+            sweepAngle = 360 - sweepAngle - MIN_SWEEP_ANGLE;
+        } else {
+            sweepAngle += MIN_SWEEP_ANGLE;
+        }
+        canvas.drawArc(fBounds, startAngle, sweepAngle, false, mPaint);
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mPaint.setAlpha(alpha);
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+        mPaint.setColorFilter(cf);
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSPARENT;
+    }
+
+    @Override
+    public void start() {
+        if (isRunning()) {
+            return;
+        }
+        mRunning = true;
+        mObjectAnimatorAngle.start();
+        mObjectAnimatorSweep.start();
+        invalidateSelf();
+    }
+
+    @Override
+    public void stop() {
+        if (!isRunning()) {
+            return;
+        }
+        mRunning = false;
+        mObjectAnimatorAngle.cancel();
+        mObjectAnimatorSweep.cancel();
+        invalidateSelf();
+    }
+
+    @Override
+    public boolean isRunning() {
+        return mRunning;
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        fBounds.left = bounds.left + mBorderWidth / 2f + .5f;
+        fBounds.right = bounds.right - mBorderWidth / 2f - .5f;
+        fBounds.top = bounds.top + mBorderWidth / 2f + .5f;
+        fBounds.bottom = bounds.bottom - mBorderWidth / 2f - .5f;
+    }
+
+    public void setCurrentGlobalAngle(float currentGlobalAngle) {
+        mCurrentGlobalAngle = currentGlobalAngle;
+        invalidateSelf();
+    }
+
+    public float getCurrentGlobalAngle() {
+        return mCurrentGlobalAngle;
+    }
+
+    public void setCurrentSweepAngle(float currentSweepAngle) {
+        mCurrentSweepAngle = currentSweepAngle;
+        invalidateSelf();
+    }
+
+    public float getCurrentSweepAngle() {
+        return mCurrentSweepAngle;
+    }
+
+    private void toggleAppearingMode() {
+        mModeAppearing = !mModeAppearing;
+        if (mModeAppearing) {
+            mCurrentGlobalAngleOffset = (mCurrentGlobalAngleOffset + MIN_SWEEP_ANGLE * 2) % 360;
+        }
+    }
+
+    //////////////////////////////////////////////////////////////////////////////
+    ////////////////            Animation
+
+    private Property<CircularProgressDrawable, Float> mAngleProperty
+            = new Property<CircularProgressDrawable, Float>(Float.class, "angle") {
+        @Override
+        public Float get(CircularProgressDrawable object) {
+            return object.getCurrentGlobalAngle();
+        }
+
+        @Override
+        public void set(CircularProgressDrawable object, Float value) {
+            object.setCurrentGlobalAngle(value);
+        }
+    };
+
+    private Property<CircularProgressDrawable, Float> mSweepProperty
+            = new Property<CircularProgressDrawable, Float>(Float.class, "arc") {
+        @Override
+        public Float get(CircularProgressDrawable object) {
+            return object.getCurrentSweepAngle();
+        }
+
+        @Override
+        public void set(CircularProgressDrawable object, Float value) {
+            object.setCurrentSweepAngle(value);
+        }
+    };
+
+    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 Animator.AnimatorListener() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+
+            }
+
+            @Override
+            public void onAnimationRepeat(Animator animation) {
+                toggleAppearingMode();
+            }
+        });
+    }
+}

+ 1 - 0
library/src/main/res/values/dimens.xml

@@ -72,5 +72,6 @@
     <dimen name="md_simplelist_icon_margin">16dp</dimen>
 
     <dimen name="md_bg_corner_radius">2dp</dimen>
+    <dimen name="circular_progress_border">4dp</dimen>
 
 </resources>