diff --git a/build.gradle b/build.gradle index 59c46b1..b7a9697 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:3.2.0' + classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' } @@ -63,7 +63,7 @@ android { } dependencies { - api 'androidx.annotation:annotation:1.0.0' + api 'androidx.annotation:annotation:1.0.1' } group = publishedGroupId diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f38c257..8deb97f 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip diff --git a/src/main/java/com/budiyev/android/circularprogressbar/CircularProgressBar.java b/src/main/java/com/budiyev/android/circularprogressbar/CircularProgressBar.java index feeb328..5ea3d23 100644 --- a/src/main/java/com/budiyev/android/circularprogressbar/CircularProgressBar.java +++ b/src/main/java/com/budiyev/android/circularprogressbar/CircularProgressBar.java @@ -68,14 +68,10 @@ public final class CircularProgressBar extends View { private static final boolean DEFAULT_ANIMATE_PROGRESS = true; private static final boolean DEFAULT_DRAW_BACKGROUND_STROKE = false; private static final boolean DEFAULT_INDETERMINATE = false; - private static final TimeInterpolator DEFAULT_PROGRESS_ANIMATION_INTERPOLATOR = new DecelerateInterpolator(); - private static final TimeInterpolator DEFAULT_SWEEP_ANIMATION_INTERPOLATOR = new LinearInterpolator(); - private static final TimeInterpolator DEFAULT_START_ANIMATION_INTERPOLATOR = new DecelerateInterpolator(); - private final Runnable mSweepRestartAction = new SweepRestartAction(); private final RectF mDrawRect = new RectF(); private final ValueAnimator mProgressAnimator = new ValueAnimator(); - private final ValueAnimator mIndeterminateStartAnimator = new ValueAnimator(); + private final ValueAnimator mIndeterminateRotationAnimator = new ValueAnimator(); private final ValueAnimator mIndeterminateSweepAnimator = new ValueAnimator(); private final Paint mForegroundStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mBackgroundStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG); @@ -128,7 +124,8 @@ public boolean isIndeterminate() { * Indeterminate mode, disabled by default */ public void setIndeterminate(final boolean indeterminate) { - stopIndeterminateAnimations(); + cancelProgressAnimation(); + cancelIndeterminateAnimations(); mIndeterminate = indeterminate; invalidate(); if (mVisible && indeterminate) { @@ -136,46 +133,6 @@ public void setIndeterminate(final boolean indeterminate) { } } - /** - * Get interpolator used by start animation in - * indeterminate mode - */ - public TimeInterpolator getIndeterminateStartInterpolator() { - return mIndeterminateStartAnimator.getInterpolator(); - } - - /** - * Set interpolation for start animator that - * are used in indeterminate mode. - */ - public void setIndeterminateStartInterpolator(final TimeInterpolator startInterpolator) { - stopIndeterminateAnimations(); - mIndeterminateStartAnimator.setInterpolator( - startInterpolator == null ? DEFAULT_START_ANIMATION_INTERPOLATOR : startInterpolator - ); - setIndeterminate(mIndeterminate); - } - - /** - * Return interpolator used by Sweep Animation in - * indeterminate mode - */ - public TimeInterpolator getIndeterminateSweepInterpolator() { - return mIndeterminateSweepAnimator.getInterpolator(); - } - - /** - * Set interpolation for sweep animator that - * are used in indeterminate mode. - */ - public void setIndeterminateSweepInterpolator(final TimeInterpolator sweepInterpolator) { - stopIndeterminateAnimations(); - mIndeterminateSweepAnimator.setInterpolator( - sweepInterpolator == null ? DEFAULT_SWEEP_ANIMATION_INTERPOLATOR : sweepInterpolator - ); - setIndeterminate(mIndeterminate); - } - /** * Get current progress value for non-indeterminate mode */ @@ -190,7 +147,7 @@ public void setProgress(final float progress) { if (mIndeterminate) { mProgress = progress; } else { - stopProgressAnimation(); + cancelProgressAnimation(); if (mVisible && mAnimateProgress) { setProgressAnimated(progress); } else { @@ -199,25 +156,6 @@ public void setProgress(final float progress) { } } - /** - * Set the current animation interpolator - */ - public void setProgressInterpolator(final TimeInterpolator interpolator) { - if (mVisible) { - if (mProgressAnimator.isRunning()) { - mProgressAnimator.end(); - } - } - mProgressAnimator.setInterpolator(interpolator == null ? DEFAULT_PROGRESS_ANIMATION_INTERPOLATOR : interpolator); - } - - /** - * Returns progress animator used to animate setting the progress - */ - public TimeInterpolator getProgressInterpolator() { - return mProgressAnimator.getInterpolator(); - } - /** * Maximum progress for non-indeterminate mode */ @@ -245,7 +183,9 @@ public float getStartAngle() { * Start angle for non-indeterminate mode, between -360 and 360 degrees */ public void setStartAngle(@FloatRange(from = -360f, to = 360f) final float angle) { - checkStartAngle(angle); + if (angle < -360f || angle > 360f) { + throw new IllegalArgumentException("Start angle value should be between -360 and 360 degrees (inclusive)"); + } mStartAngle = angle; invalidate(); } @@ -276,15 +216,37 @@ public long getProgressAnimationDuration() { * Progress animation duration for non-indeterminate mode (in milliseconds) */ public void setProgressAnimationDuration(@IntRange(from = 0) final long duration) { - checkAnimationDuration(duration); + if (duration < 0) { + throw new IllegalArgumentException("Animation duration can't be negative"); + } if (mVisible) { - if (mProgressAnimator.isRunning()) { - mProgressAnimator.end(); - } + endProgressAnimation(); } mProgressAnimator.setDuration(duration); } + /** + * Progress animation interpolator for non-indeterminate mode + */ + @NonNull + public TimeInterpolator getProgressAnimationInterpolator() { + return mProgressAnimator.getInterpolator(); + } + + /** + * Progress animation interpolator for non-indeterminate mode + */ + public void setProgressAnimationInterpolator(@NonNull TimeInterpolator interpolator) { + //noinspection ConstantConditions + if (interpolator == null) { + throw new IllegalArgumentException("Interpolator can't be null"); + } + if (mVisible) { + endProgressAnimation(); + } + mProgressAnimator.setInterpolator(interpolator); + } + /** * Minimum angle for indeterminate mode, between 0 and 180 degrees */ @@ -297,8 +259,11 @@ public float getIndeterminateMinimumAngle() { * Minimum angle for indeterminate mode, between 0 and 180 degrees */ public void setIndeterminateMinimumAngle(@FloatRange(from = 0f, to = 180f) final float angle) { - checkIndeterminateMinimumAngle(angle); - stopIndeterminateAnimations(); + if (angle < 0f || angle > 180f) { + throw new IllegalArgumentException( + "Indeterminate minimum angle value should be between 0 and 180 degrees (inclusive)"); + } + cancelIndeterminateAnimations(); mIndeterminateMinimumAngle = angle; mIndeterminateSweepAnimator.setFloatValues(360f - angle * 2f); invalidate(); @@ -312,16 +277,42 @@ public void setIndeterminateMinimumAngle(@FloatRange(from = 0f, to = 180f) final */ @IntRange(from = 0) public long getIndeterminateRotationAnimationDuration() { - return mIndeterminateStartAnimator.getDuration(); + return mIndeterminateRotationAnimator.getDuration(); } /** * Rotation animation duration for indeterminate mode (in milliseconds) */ public void setIndeterminateRotationAnimationDuration(@IntRange(from = 0) final long duration) { - checkAnimationDuration(duration); - stopIndeterminateAnimations(); - mIndeterminateStartAnimator.setDuration(duration); + if (duration < 0) { + throw new IllegalArgumentException("Animation duration can't be negative"); + } + cancelIndeterminateAnimations(); + mIndeterminateRotationAnimator.setDuration(duration); + invalidate(); + if (mVisible && mIndeterminate) { + startIndeterminateAnimations(); + } + } + + /** + * Rotation animation interpolator for indeterminate mode + */ + @NonNull + public TimeInterpolator getIndeterminateRotationAnimationInterpolator() { + return mIndeterminateRotationAnimator.getInterpolator(); + } + + /** + * Rotation animation interpolator for indeterminate mode + */ + public void setIndeterminateRotationAnimationInterpolator(@NonNull TimeInterpolator interpolator) { + //noinspection ConstantConditions + if (interpolator == null) { + throw new IllegalArgumentException("Interpolator can't be null"); + } + cancelIndeterminateAnimations(); + mIndeterminateRotationAnimator.setInterpolator(interpolator); invalidate(); if (mVisible && mIndeterminate) { startIndeterminateAnimations(); @@ -340,8 +331,10 @@ public long getIndeterminateSweepAnimationDuration() { * Sweep animation duration for indeterminate mode (in milliseconds) */ public void setIndeterminateSweepAnimationDuration(@IntRange(from = 0) final long duration) { - checkAnimationDuration(duration); - stopIndeterminateAnimations(); + if (duration < 0) { + throw new IllegalArgumentException("Animation duration can't be negative"); + } + cancelIndeterminateAnimations(); mIndeterminateSweepAnimator.setDuration(duration); invalidate(); if (mVisible && mIndeterminate) { @@ -349,6 +342,30 @@ public void setIndeterminateSweepAnimationDuration(@IntRange(from = 0) final lon } } + /** + * Sweep animation interpolator for indeterminate mode + */ + @NonNull + public TimeInterpolator getIndeterminateSweepAnimationInterpolator() { + return mIndeterminateSweepAnimator.getInterpolator(); + } + + /** + * Sweep animation interpolator for indeterminate mode + */ + public void setIndeterminateSweepAnimationInterpolator(@NonNull TimeInterpolator interpolator) { + //noinspection ConstantConditions + if (interpolator == null) { + throw new IllegalArgumentException("Interpolator can't be null"); + } + cancelIndeterminateAnimations(); + mIndeterminateSweepAnimator.setInterpolator(interpolator); + invalidate(); + if (mVisible && mIndeterminate) { + startIndeterminateAnimations(); + } + } + /** * Foreground stroke cap */ @@ -361,6 +378,10 @@ public Paint.Cap getForegroundStrokeCap() { * Foreground stroke cap */ public void setForegroundStrokeCap(@NonNull final Paint.Cap cap) { + //noinspection ConstantConditions + if (cap == null) { + throw new IllegalArgumentException("Cap can't be null"); + } mForegroundStrokePaint.setStrokeCap(cap); invalidateForegroundStrokeCapAngle(); invalidate(); @@ -394,7 +415,9 @@ public float getForegroundStrokeWidth() { * Foreground stroke width (in pixels) */ public void setForegroundStrokeWidth(@FloatRange(from = 0f, to = Float.MAX_VALUE) final float width) { - checkWidth(width); + if (width < 0f) { + throw new IllegalArgumentException("Width can't be negative"); + } mForegroundStrokePaint.setStrokeWidth(width); invalidateDrawRect(); invalidate(); @@ -428,7 +451,9 @@ public float getBackgroundStrokeWidth() { * Background stroke width (in pixels) */ public void setBackgroundStrokeWidth(@FloatRange(from = 0f, to = Float.MAX_VALUE) final float width) { - checkWidth(width); + if (width < 0f) { + throw new IllegalArgumentException("Width can't be negative"); + } mBackgroundStrokePaint.setStrokeWidth(width); invalidateDrawRect(); invalidate(); @@ -458,8 +483,10 @@ public void onVisibilityAggregated(final boolean visible) { if (visible) { startIndeterminateAnimations(); } else { - stopIndeterminateAnimations(); + cancelIndeterminateAnimations(); } + } else if (!visible) { + endProgressAnimation(); } } @@ -574,8 +601,8 @@ protected void onAttachedToWindow() { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); mVisible = false; - stopIndeterminateAnimations(); - stopProgressAnimation(); + cancelIndeterminateAnimations(); + cancelProgressAnimation(); } private void initialize(@NonNull final Context context, @Nullable final AttributeSet attributeSet, @@ -600,7 +627,7 @@ private void initialize(@NonNull final Context context, @Nullable final Attribut mBackgroundStrokePaint.setColor(DEFAULT_BACKGROUND_STROKE_COLOR); mBackgroundStrokePaint .setStrokeWidth(Math.round(DEFAULT_BACKGROUND_STROKE_WIDTH_DP * displayMetrics.density)); - mIndeterminateStartAnimator.setDuration(DEFAULT_INDETERMINATE_ROTATION_ANIMATION_DURATION); + mIndeterminateRotationAnimator.setDuration(DEFAULT_INDETERMINATE_ROTATION_ANIMATION_DURATION); mIndeterminateSweepAnimator.setDuration(DEFAULT_INDETERMINATE_SWEEP_ANIMATION_DURATION); } else { TypedArray attributes = null; @@ -608,71 +635,52 @@ private void initialize(@NonNull final Context context, @Nullable final Attribut attributes = context.getTheme() .obtainStyledAttributes(attributeSet, R.styleable.CircularProgressBar, defStyleAttr, defStyleRes); - mMaximum = attributes.getFloat(R.styleable.CircularProgressBar_maximum, DEFAULT_MAXIMUM); - mProgress = attributes.getFloat(R.styleable.CircularProgressBar_progress, DEFAULT_PROGRESS); - final float startAngle = - attributes.getFloat(R.styleable.CircularProgressBar_startAngle, DEFAULT_START_ANGLE); - checkStartAngle(startAngle); - mStartAngle = startAngle; - final float minimumAngle = attributes + setMaximum(attributes.getFloat(R.styleable.CircularProgressBar_maximum, DEFAULT_MAXIMUM)); + setProgress(attributes.getFloat(R.styleable.CircularProgressBar_progress, DEFAULT_PROGRESS)); + setStartAngle(attributes.getFloat(R.styleable.CircularProgressBar_startAngle, DEFAULT_START_ANGLE)); + setIndeterminateMinimumAngle(attributes .getFloat(R.styleable.CircularProgressBar_indeterminateMinimumAngle, - DEFAULT_INDETERMINATE_MINIMUM_ANGLE); - checkIndeterminateMinimumAngle(minimumAngle); - mIndeterminateMinimumAngle = minimumAngle; - final long progressDuration = attributes + DEFAULT_INDETERMINATE_MINIMUM_ANGLE)); + setProgressAnimationDuration(attributes .getInteger(R.styleable.CircularProgressBar_progressAnimationDuration, - DEFAULT_PROGRESS_ANIMATION_DURATION); - checkAnimationDuration(progressDuration); - mProgressAnimator.setDuration(progressDuration); - final long rotationDuration = attributes + DEFAULT_PROGRESS_ANIMATION_DURATION)); + setIndeterminateRotationAnimationDuration(attributes .getInteger(R.styleable.CircularProgressBar_indeterminateRotationAnimationDuration, - DEFAULT_INDETERMINATE_ROTATION_ANIMATION_DURATION); - checkAnimationDuration(rotationDuration); - mIndeterminateStartAnimator.setDuration(rotationDuration); - final long sweepDuration = attributes + DEFAULT_INDETERMINATE_ROTATION_ANIMATION_DURATION)); + setIndeterminateSweepAnimationDuration(attributes .getInteger(R.styleable.CircularProgressBar_indeterminateSweepAnimationDuration, - DEFAULT_INDETERMINATE_SWEEP_ANIMATION_DURATION); - checkAnimationDuration(sweepDuration); - mIndeterminateSweepAnimator.setDuration(sweepDuration); - mForegroundStrokePaint.setColor(attributes - .getColor(R.styleable.CircularProgressBar_foregroundStrokeColor, - DEFAULT_FOREGROUND_STROKE_COLOR)); - mBackgroundStrokePaint.setColor(attributes - .getColor(R.styleable.CircularProgressBar_backgroundStrokeColor, - DEFAULT_BACKGROUND_STROKE_COLOR)); - final float foregroundWidth = attributes - .getDimension(R.styleable.CircularProgressBar_foregroundStrokeWidth, - Math.round(DEFAULT_FOREGROUND_STROKE_WIDTH_DP * displayMetrics.density)); - checkWidth(foregroundWidth); - mForegroundStrokePaint.setStrokeWidth(foregroundWidth); - mForegroundStrokePaint.setStrokeCap(getStrokeCap(attributes + DEFAULT_INDETERMINATE_SWEEP_ANIMATION_DURATION)); + setForegroundStrokeColor(attributes.getColor(R.styleable.CircularProgressBar_foregroundStrokeColor, + DEFAULT_FOREGROUND_STROKE_COLOR)); + setBackgroundStrokeColor(attributes.getColor(R.styleable.CircularProgressBar_backgroundStrokeColor, + DEFAULT_BACKGROUND_STROKE_COLOR)); + setForegroundStrokeWidth(attributes.getDimension(R.styleable.CircularProgressBar_foregroundStrokeWidth, + Math.round(DEFAULT_FOREGROUND_STROKE_WIDTH_DP * displayMetrics.density))); + setForegroundStrokeCap(getStrokeCap(attributes .getInt(R.styleable.CircularProgressBar_foregroundStrokeCap, DEFAULT_FOREGROUND_STROKE_CAP))); - final float backgroundWidth = attributes - .getDimension(R.styleable.CircularProgressBar_backgroundStrokeWidth, - Math.round(DEFAULT_BACKGROUND_STROKE_WIDTH_DP * displayMetrics.density)); - checkWidth(backgroundWidth); - mBackgroundStrokePaint.setStrokeWidth(backgroundWidth); - mAnimateProgress = attributes - .getBoolean(R.styleable.CircularProgressBar_animateProgress, DEFAULT_ANIMATE_PROGRESS); - mDrawBackgroundStroke = attributes.getBoolean(R.styleable.CircularProgressBar_drawBackgroundStroke, - DEFAULT_DRAW_BACKGROUND_STROKE); - mIndeterminate = - attributes.getBoolean(R.styleable.CircularProgressBar_indeterminate, DEFAULT_INDETERMINATE); + setBackgroundStrokeWidth(attributes.getDimension(R.styleable.CircularProgressBar_backgroundStrokeWidth, + Math.round(DEFAULT_BACKGROUND_STROKE_WIDTH_DP * displayMetrics.density))); + setAnimateProgress(attributes + .getBoolean(R.styleable.CircularProgressBar_animateProgress, DEFAULT_ANIMATE_PROGRESS)); + setDrawBackgroundStroke(attributes.getBoolean(R.styleable.CircularProgressBar_drawBackgroundStroke, + DEFAULT_DRAW_BACKGROUND_STROKE)); + setIndeterminate( + attributes.getBoolean(R.styleable.CircularProgressBar_indeterminate, DEFAULT_INDETERMINATE)); } finally { if (attributes != null) { attributes.recycle(); } } } - mProgressAnimator.setInterpolator(DEFAULT_PROGRESS_ANIMATION_INTERPOLATOR); + mProgressAnimator.setInterpolator(new DecelerateInterpolator()); mProgressAnimator.addUpdateListener(new ProgressUpdateListener()); - mIndeterminateStartAnimator.setFloatValues(360f); - mIndeterminateStartAnimator.setRepeatMode(ValueAnimator.RESTART); - mIndeterminateStartAnimator.setRepeatCount(ValueAnimator.INFINITE); - mIndeterminateStartAnimator.setInterpolator(DEFAULT_START_ANIMATION_INTERPOLATOR); - mIndeterminateStartAnimator.addUpdateListener(new StartUpdateListener()); + mIndeterminateRotationAnimator.setFloatValues(360f); + mIndeterminateRotationAnimator.setRepeatMode(ValueAnimator.RESTART); + mIndeterminateRotationAnimator.setRepeatCount(ValueAnimator.INFINITE); + mIndeterminateRotationAnimator.setInterpolator(new DecelerateInterpolator()); + mIndeterminateRotationAnimator.addUpdateListener(new StartUpdateListener()); mIndeterminateSweepAnimator.setFloatValues(360f - mIndeterminateMinimumAngle * 2f); - mIndeterminateSweepAnimator.setInterpolator(DEFAULT_SWEEP_ANIMATION_INTERPOLATOR); + mIndeterminateSweepAnimator.setInterpolator(new LinearInterpolator()); mIndeterminateSweepAnimator.addUpdateListener(new SweepUpdateListener()); mIndeterminateSweepAnimator.addListener(new SweepAnimatorListener()); } @@ -742,15 +750,21 @@ private void setProgressAnimated(final float progress) { mProgressAnimator.start(); } - private void stopProgressAnimation() { + private void endProgressAnimation() { + if (mProgressAnimator.isRunning()) { + mProgressAnimator.end(); + } + } + + private void cancelProgressAnimation() { if (mProgressAnimator.isRunning()) { mProgressAnimator.cancel(); } } - private void stopIndeterminateAnimations() { - if (mIndeterminateStartAnimator.isRunning()) { - mIndeterminateStartAnimator.cancel(); + private void cancelIndeterminateAnimations() { + if (mIndeterminateRotationAnimator.isRunning()) { + mIndeterminateRotationAnimator.cancel(); } if (mIndeterminateSweepAnimator.isRunning()) { mIndeterminateSweepAnimator.cancel(); @@ -758,39 +772,14 @@ private void stopIndeterminateAnimations() { } private void startIndeterminateAnimations() { - if (!mIndeterminateStartAnimator.isRunning()) { - mIndeterminateStartAnimator.start(); + if (!mIndeterminateRotationAnimator.isRunning()) { + mIndeterminateRotationAnimator.start(); } if (!mIndeterminateSweepAnimator.isRunning()) { mIndeterminateSweepAnimator.start(); } } - private static void checkStartAngle(final float angle) { - if (angle < -360f || angle > 360f) { - throw new IllegalArgumentException("Start angle value should be between -360 and 360 degrees (inclusive)"); - } - } - - private static void checkIndeterminateMinimumAngle(final float angle) { - if (angle < 0f || angle > 180f) { - throw new IllegalArgumentException( - "Indeterminate minimum angle value should be between 0 and 180 degrees (inclusive)"); - } - } - - private static void checkAnimationDuration(final long duration) { - if (duration < 0) { - throw new IllegalArgumentException("Animation duration can't be negative"); - } - } - - private static void checkWidth(final float width) { - if (width < 0f) { - throw new IllegalArgumentException("Width can't be negative"); - } - } - @NonNull private static Paint.Cap getStrokeCap(final int value) { switch (value) {