diff --git a/CHANGELOG.md b/CHANGELOG.md index f94d68f..4fb61d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +##0.5.0 + +- Added a gradient option via XML and JAVA + ##0.4.0 - Added a `progressStart()` and `progressStop()` methods diff --git a/gradle.properties b/gradle.properties index dfab4a2..c41fcb3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ -VERSION_NAME=0.5.0-SNAPSHOT -VERSION_CODE=12 +VERSION_NAME=0.5.0 +VERSION_CODE=13 BUILD_TOOLS_VERSION=19.0.3 COMPILE_SDK_VERSION=19 GROUP=com.github.castorflex.smoothprogressbar diff --git a/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressBar.java b/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressBar.java index 3949e34..c359be9 100644 --- a/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressBar.java +++ b/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressBar.java @@ -57,6 +57,7 @@ public SmoothProgressBar(Context context, AttributeSet attrs, int defStyle) { final boolean progressiveStartActivated = a.getBoolean(R.styleable.SmoothProgressBar_spb_progressiveStart_activated, res.getBoolean(R.bool.spb_default_progressiveStart_activated)); final Drawable backgroundDrawable = a.getDrawable(R.styleable.SmoothProgressBar_spb_background); final boolean generateBackgroundWithColors = a.getBoolean(R.styleable.SmoothProgressBar_spb_generate_background_with_colors, false); + final boolean gradients = a.getBoolean(R.styleable.SmoothProgressBar_spb_gradients, false); a.recycle(); //interpolator @@ -97,7 +98,8 @@ public SmoothProgressBar(Context context, AttributeSet attrs, int defStyle) { .strokeWidth(strokeWidth) .reversed(reversed) .mirrorMode(mirrorMode) - .progressiveStart(progressiveStartActivated); + .progressiveStart(progressiveStartActivated) + .gradients(gradients); if (backgroundDrawable != null) { builder.backgroundDrawable(backgroundDrawable); @@ -157,8 +159,11 @@ public void applyStyle(int styleResId) { if (a.hasValue(R.styleable.SmoothProgressBar_spb_progressiveStart_activated)) { setProgressiveStartActivated(a.getBoolean(R.styleable.SmoothProgressBar_spb_progressiveStart_activated, false)); } - if (a.hasValue(R.styleable.SmoothProgressBar_spb_background)) { - setSmoothProgressDrawableBackgroundDrawable(a.getDrawable(R.styleable.SmoothProgressBar_spb_background)); + if (a.hasValue(R.styleable.SmoothProgressBar_spb_progressiveStart_activated)) { + setProgressiveStartActivated(a.getBoolean(R.styleable.SmoothProgressBar_spb_progressiveStart_activated, false)); + } + if (a.hasValue(R.styleable.SmoothProgressBar_spb_gradients)) { + setSmoothProgressDrawableUseGradients(a.getBoolean(R.styleable.SmoothProgressBar_spb_gradients, false)); } if (a.hasValue(R.styleable.SmoothProgressBar_spb_generate_background_with_colors)) { if (a.getBoolean(R.styleable.SmoothProgressBar_spb_generate_background_with_colors, false)) { @@ -272,6 +277,10 @@ public void setSmoothProgressDrawableBackgroundDrawable(Drawable drawable) { checkIndeterminateDrawable().setBackgroundDrawable(drawable); } + public void setSmoothProgressDrawableUseGradients(boolean useGradients) { + checkIndeterminateDrawable().setUseGradients(useGradients); + } + public void progressiveStart() { checkIndeterminateDrawable().progressiveStart(); } diff --git a/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressDrawable.java b/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressDrawable.java index e609663..af01ed2 100644 --- a/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressDrawable.java +++ b/library/src/main/java/fr/castorflex/android/smoothprogressbar/SmoothProgressDrawable.java @@ -4,9 +4,11 @@ import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.ColorFilter; +import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.Shader; import android.graphics.drawable.Animatable; import android.graphics.drawable.Drawable; import android.os.SystemClock; @@ -52,6 +54,9 @@ public interface Callbacks { private int mCurrentSections; private float mStrokeWidth; private Drawable mBackgroundDrawable; + private boolean mUseGradients; + private int[] mLinearGradientColors; + private float[] mLinearGradientPositions; private SmoothProgressDrawable(Interpolator interpolator, @@ -66,7 +71,8 @@ private SmoothProgressDrawable(Interpolator interpolator, boolean mirrorMode, Callbacks callbacks, boolean progressiveStartActivated, - Drawable backgroundDrawable) { + Drawable backgroundDrawable, + boolean useGradients) { mRunning = false; mInterpolator = interpolator; mSectionsCount = sectionsCount; @@ -94,6 +100,9 @@ private SmoothProgressDrawable(Interpolator interpolator, mProgressiveStartActivated = progressiveStartActivated; mCallbacks = callbacks; + + mUseGradients = useGradients; + refreshLinearGradientOptions(); } //////////////////////////////////////////////////////////////////////////// @@ -109,6 +118,7 @@ public void setColors(int[] colors) { throw new IllegalArgumentException("Colors cannot be null or empty"); mColorsIndex = 0; mColors = colors; + refreshLinearGradientOptions(); invalidateSelf(); } @@ -139,6 +149,7 @@ public void setSectionsCount(int sectionsCount) { mSectionsCount = sectionsCount; mMaxOffset = 1f / mSectionsCount; mCurrentOffset %= mMaxOffset; + refreshLinearGradientOptions(); invalidateSelf(); } @@ -189,6 +200,25 @@ public void setProgressiveStartActivated(boolean progressiveStartActivated) { mProgressiveStartActivated = progressiveStartActivated; } + public void setUseGradients(boolean useGradients) { + if (mUseGradients == useGradients) return; + + mUseGradients = useGradients; + refreshLinearGradientOptions(); + invalidateSelf(); + } + + protected void refreshLinearGradientOptions() { + if (mUseGradients) { + mLinearGradientColors = new int[mSectionsCount + 2]; + mLinearGradientPositions = new float[mSectionsCount + 2]; + } else { + mPaint.setShader(null); + mLinearGradientColors = null; + mLinearGradientPositions = null; + } + } + //////////////////////////////////////////////////////////////////////////// /////////////////// DRAW @@ -197,24 +227,6 @@ public void draw(Canvas canvas) { mBounds = getBounds(); canvas.clipRect(mBounds); - int boundsWidth = mBounds.width(); - - if (mReversed) { - canvas.translate(boundsWidth, 0); - canvas.scale(-1, 1); - } - - drawStrokes(canvas); - } - - private void drawStrokes(Canvas canvas) { - float prevValue = 0f; - int boundsWidth = mBounds.width(); - if (mMirrorMode) boundsWidth /= 2; - int width = boundsWidth + mSeparatorLength + mSectionsCount; - int centerY = mBounds.centerY(); - float xSectionWidth = 1f / mSectionsCount; - //new turn if (mNewTurn) { mColorsIndex = decrementColor(mColorsIndex); @@ -233,6 +245,58 @@ private void drawStrokes(Canvas canvas) { } } + if (mUseGradients) + drawGradient(canvas); + + drawStrokes(canvas); + } + + private void drawGradient(Canvas canvas) { + float xSectionWidth = 1f / mSectionsCount; + int currentIndexColor = mColorsIndex; + + mLinearGradientPositions[0] = 0f; + mLinearGradientPositions[mLinearGradientPositions.length - 1] = 1f; + int firstColorIndex = currentIndexColor - 1; + if (firstColorIndex < 0) firstColorIndex += mColors.length; + + mLinearGradientColors[0] = mColors[firstColorIndex]; + + for (int i = 0; i < mSectionsCount; ++i) { + + float position = mInterpolator.getInterpolation(i * xSectionWidth + mCurrentOffset); + mLinearGradientPositions[i + 1] = position; + mLinearGradientColors[i + 1] = mColors[currentIndexColor]; + + currentIndexColor = (currentIndexColor + 1) % mColors.length; + } + mLinearGradientColors[mLinearGradientColors.length - 1] = mColors[currentIndexColor]; + + float left = mReversed ? (mMirrorMode ? Math.abs(mBounds.left - mBounds.right) / 2 : mBounds.right) : mBounds.left; + float right = mMirrorMode ? (mReversed ? mBounds.left : Math.abs(mBounds.left - mBounds.right) / 2) : + (mReversed ? mBounds.left : mBounds.right); + float top = mBounds.centerY() - mStrokeWidth / 2; + float bottom = mBounds.centerY() + mStrokeWidth / 2; + LinearGradient linearGradient = new LinearGradient(left, top, right, bottom, + mLinearGradientColors, mLinearGradientPositions, + mMirrorMode ? Shader.TileMode.MIRROR : Shader.TileMode.CLAMP); + + mPaint.setShader(linearGradient); + } + + private void drawStrokes(Canvas canvas) { + if (mReversed) { + canvas.translate(mBounds.width(), 0); + canvas.scale(-1, 1); + } + + float prevValue = 0f; + int boundsWidth = mBounds.width(); + if (mMirrorMode) boundsWidth /= 2; + int width = boundsWidth + mSeparatorLength + mSectionsCount; + int centerY = mBounds.centerY(); + float xSectionWidth = 1f / mSectionsCount; + float startX; float endX; float firstX = 0; @@ -547,6 +611,7 @@ public static class Builder { private int mStrokeSeparatorLength; private boolean mProgressiveStartActivated; private boolean mGenerateBackgroundUsingColors; + private boolean mGradients; private Drawable mBackgroundDrawableWhenHidden; private Callbacks mOnProgressiveStopEndedListener; @@ -572,7 +637,8 @@ public SmoothProgressDrawable build() { mMirrorMode, mOnProgressiveStopEndedListener, mProgressiveStartActivated, - mBackgroundDrawableWhenHidden); + mBackgroundDrawableWhenHidden, + mGradients); return ret; } @@ -588,6 +654,7 @@ private void initValues(Context context) { mStrokeSeparatorLength = res.getDimensionPixelSize(R.dimen.spb_default_stroke_separator_length); mStrokeWidth = res.getDimensionPixelOffset(R.dimen.spb_default_stroke_width); mProgressiveStartActivated = res.getBoolean(R.bool.spb_default_progressiveStart_activated); + mGradients = false; } public Builder interpolator(Interpolator interpolator) { @@ -677,5 +744,14 @@ public Builder generateBackgroundUsingColors() { mGenerateBackgroundUsingColors = true; return this; } + + public Builder gradients() { + return gradients(true); + } + + public Builder gradients(boolean useGradients) { + mGradients = useGradients; + return this; + } } } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index a037423..0d309c5 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -21,5 +21,6 @@ + \ No newline at end of file diff --git a/library/src/main/res/values/styles.xml b/library/src/main/res/values/styles.xml index 3b91cb9..1816559 100644 --- a/library/src/main/res/values/styles.xml +++ b/library/src/main/res/values/styles.xml @@ -16,6 +16,7 @@ @bool/spb_default_progressiveStart_activated @null false + false \ No newline at end of file diff --git a/sample/src/main/java/fr/castorflex/android/smoothprogressbar/sample/MakeCustomActivity.java b/sample/src/main/java/fr/castorflex/android/smoothprogressbar/sample/MakeCustomActivity.java index 5621d91..fcb7363 100644 --- a/sample/src/main/java/fr/castorflex/android/smoothprogressbar/sample/MakeCustomActivity.java +++ b/sample/src/main/java/fr/castorflex/android/smoothprogressbar/sample/MakeCustomActivity.java @@ -27,6 +27,7 @@ public class MakeCustomActivity extends Activity { private SmoothProgressBar mProgressBar; private CheckBox mCheckBoxMirror; private CheckBox mCheckBoxReversed; + private CheckBox mCheckBoxGradients; private Spinner mSpinnerInterpolators; private SeekBar mSeekBarSectionsCount; private SeekBar mSeekBarStrokeWidth; @@ -52,6 +53,7 @@ protected void onCreate(Bundle savedInstanceState) { mProgressBar = (SmoothProgressBar) findViewById(R.id.progressbar); mCheckBoxMirror = (CheckBox) findViewById(R.id.checkbox_mirror); mCheckBoxReversed = (CheckBox) findViewById(R.id.checkbox_reversed); + mCheckBoxGradients = (CheckBox) findViewById(R.id.checkbox_gradients); mSpinnerInterpolators = (Spinner) findViewById(R.id.spinner_interpolator); mSeekBarSectionsCount = (SeekBar) findViewById(R.id.seekbar_sections_count); mSeekBarStrokeWidth = (SeekBar) findViewById(R.id.seekbar_stroke_width); @@ -159,6 +161,7 @@ private void setValues() { mProgressBar.setSmoothProgressDrawableStrokeWidth(dpToPx(mStrokeWidth)); mProgressBar.setSmoothProgressDrawableReversed(mCheckBoxReversed.isChecked()); mProgressBar.setSmoothProgressDrawableMirrorMode(mCheckBoxMirror.isChecked()); + mProgressBar.setSmoothProgressDrawableUseGradients(mCheckBoxGradients.isChecked()); Interpolator interpolator; switch (mSpinnerInterpolators.getSelectedItemPosition()) { diff --git a/sample/src/main/res/layout/activity_custom.xml b/sample/src/main/res/layout/activity_custom.xml index 022e26c..e10e738 100644 --- a/sample/src/main/res/layout/activity_custom.xml +++ b/sample/src/main/res/layout/activity_custom.xml @@ -38,6 +38,13 @@ android:layout_height="wrap_content" android:layout_weight="1" android:text="Mirror Mode"/> + + diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 9f4be7b..3d3c9f6 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -67,6 +67,18 @@ style="@style/GNowProgressBar" android:indeterminate="true"/> + + + + false + +