diff --git a/README.md b/README.md index 2463619..4fe095b 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,9 @@ circularProgress.setProgress(5000, 10000); // you can get progress values using following getters circularProgress.getProgress() // returns 5000 circularProgress.getMaxProgress() // returns 10000 + +// you can also set a visual gap between the progress and background strokes +circularProgress.setProgressGap(100); ``` #### Attributes @@ -105,6 +108,7 @@ circularProgress.getMaxProgress() // returns 10000 | Dot width | `app:dotWidth` | setters: `setDotWidthDp(widthInDp)` or `setDotWidthPx(widthInPx)`
getter: `getDotWidth()` (returns width in pixels) | same as progress stroke width | | Progress text size | `app:textSize` | setters: `setTextSizeSp(sizeInSp)` or `setTextSizePx(sizeInPx)`
getter: `getTextSize()` (returns size in pixels) | `24sp` | | Progress text color | `app:textColor` | setter: `setTextColor(textColor)`
getter: `getTextColor()` | same as progress color | +| Whether to show text | `app:showText` | setter: `setShowTextEnabled(enabled)`
getter: `isShowTextEnabled()` | `true` | | Formatting pattern to be used in `PatternProgressTextAdapter`. Checkout [Formatting progress text](#formatting-progress-text) section. | `app:formattingPattern` | setter: `setProgressTextAdapter(progressTextAdapter)`
getter: `getProgressTextAdapter()` | not specified | | Direction of the progress arc (`clockwise` or `counterclockwise`) | `app:direction` | setter: `setDirection(direction)`
getter: `getDirection()` | `counterclockwise` | | Start angle. Checkout [Start angle](#setting-start-angle) section. | `app:startAngle` | setter: `setStartAngle(startAngle)`
getter: `getStartAngle()` | `270` | @@ -245,6 +249,11 @@ circularProgress.setGradient(gradientType, endColor); circularProgress.getGradientType(); //returns LINEAR_GRADIENT ``` +Or, for advanced gradients with multiple colors and optional color positions, in code: +```java +circularProgress.setGradient(type, new int[]{Color.BLUE, Color.MAGENTA, Color.RED}, new float[]{0f, .3f, .7f}); +``` + --- ### Download using Gradle diff --git a/build.gradle b/build.gradle index 0dec223..4f923ee 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.3' + classpath 'com.android.tools.build:gradle:7.1.2' classpath 'com.github.dcendents:android-maven-gradle-plugin:2.0' // NOTE: Do not place your application dependencies here; they belong diff --git a/circularprogressindicator/build.gradle b/circularprogressindicator/build.gradle index 00cf015..784e861 100644 --- a/circularprogressindicator/build.gradle +++ b/circularprogressindicator/build.gradle @@ -1,15 +1,11 @@ apply plugin: 'com.android.library' apply plugin: 'com.github.dcendents.android-maven' -group='com.github.antonKozyriatskyi.CircularProgressIndicator' android { - compileSdkVersion 27 + compileSdkVersion 31 defaultConfig { minSdkVersion 15 - targetSdkVersion 27 - versionCode 1 - versionName "1.0" } buildTypes { @@ -23,5 +19,5 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:support-annotations:27.1.1' + implementation 'androidx.annotation:annotation:1.3.0' } diff --git a/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/CircularProgressIndicator.java b/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/CircularProgressIndicator.java index 28e44e4..f9ab977 100644 --- a/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/CircularProgressIndicator.java +++ b/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/CircularProgressIndicator.java @@ -4,6 +4,7 @@ import android.animation.PropertyValuesHolder; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; +import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; @@ -18,12 +19,6 @@ import android.graphics.Shader; import android.graphics.SweepGradient; import android.os.Build; -import android.support.annotation.ColorInt; -import android.support.annotation.Dimension; -import android.support.annotation.IntDef; -import android.support.annotation.IntRange; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.text.TextPaint; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -32,6 +27,14 @@ import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.Interpolator; +import androidx.annotation.ColorInt; +import androidx.annotation.Dimension; +import androidx.annotation.IntDef; +import androidx.annotation.IntRange; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.Size; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -39,7 +42,7 @@ * Created by Anton on 03.03.2018. */ -@SuppressWarnings("FieldCanBeLocal") +@SuppressWarnings({"FieldCanBeLocal", "unused"}) public class CircularProgressIndicator extends View { public static final int DIRECTION_CLOCKWISE = 0; @@ -75,7 +78,7 @@ public class CircularProgressIndicator extends View { private Paint textPaint; private int startAngle = DEFAULT_PROGRESS_START_ANGLE; - private int sweepAngle = 0; + private float sweepAngle = 0; private RectF circleBounds; @@ -89,16 +92,22 @@ public class CircularProgressIndicator extends View { private double maxProgressValue = 100.0; private double progressValue = 0.0; + private double progressGap = 0.0; private boolean isAnimationEnabled; private boolean isFillBackgroundEnabled; + private int animationDuration = DEFAULT_ANIMATION_DURATION; + + private boolean isShowTextEnabled = true; + @Direction private int direction = DIRECTION_COUNTERCLOCKWISE; private ValueAnimator progressAnimator; + @SuppressWarnings("NotNullFieldNotInitialized") // initialized in init method @NonNull private ProgressTextAdapter progressTextAdapter; @@ -108,6 +117,9 @@ public class CircularProgressIndicator extends View { @NonNull private Interpolator animationInterpolator = new AccelerateDecelerateInterpolator(); + @NonNull + private final Rect textBoundsRect = new Rect(); + public CircularProgressIndicator(Context context) { super(context); init(context, null); @@ -165,6 +177,7 @@ private void init(@NonNull Context context, @Nullable AttributeSet attrs) { isAnimationEnabled = a.getBoolean(R.styleable.CircularProgressIndicator_enableProgressAnimation, true); isFillBackgroundEnabled = a.getBoolean(R.styleable.CircularProgressIndicator_fillBackground, false); + isShowTextEnabled = a.getBoolean(R.styleable.CircularProgressIndicator_showText, true); direction = a.getInt(R.styleable.CircularProgressIndicator_direction, DIRECTION_COUNTERCLOCKWISE); @@ -188,12 +201,7 @@ private void init(@NonNull Context context, @Nullable AttributeSet attrs) { throw new IllegalArgumentException("did you forget to specify gradientColorEnd?"); } - post(new Runnable() { - @Override - public void run() { - setGradient(gradientType, gradientColorEnd); - } - }); + post(() -> setGradient(gradientType, gradientColorEnd)); } a.recycle(); @@ -208,6 +216,7 @@ public void run() { Paint.Style progressBackgroundStyle = isFillBackgroundEnabled ? Paint.Style.FILL_AND_STROKE : Paint.Style.STROKE; progressBackgroundPaint = new Paint(); + progressBackgroundPaint.setStrokeCap(progressStrokeCap); progressBackgroundPaint.setStyle(progressBackgroundStyle); progressBackgroundPaint.setStrokeWidth(progressBackgroundStrokeWidth); progressBackgroundPaint.setColor(progressBackgroundColor); @@ -229,6 +238,7 @@ public void run() { circleBounds = new RectF(); } + @SuppressLint("SwitchIntDef") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); @@ -244,10 +254,8 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); - Rect textBoundsRect = new Rect(); textPaint.getTextBounds(progressText, 0, progressText.length(), textBoundsRect); - float dotWidth = dotPaint.getStrokeWidth(); float progressWidth = progressPaint.getStrokeWidth(); float progressBackgroundWidth = progressBackgroundPaint.getStrokeWidth(); @@ -335,12 +343,26 @@ protected void onDraw(Canvas canvas) { drawProgressBackground(canvas); drawProgress(canvas); if (shouldDrawDot) drawDot(canvas); - drawText(canvas); + if (isShowTextEnabled) drawText(canvas); } private void drawProgressBackground(Canvas canvas) { - canvas.drawArc(circleBounds, ANGLE_START_PROGRESS_BACKGROUND, ANGLE_END_PROGRESS_BACKGROUND, - false, progressBackgroundPaint); + if (progressGap == 0) { + canvas.drawArc(circleBounds, ANGLE_START_PROGRESS_BACKGROUND, ANGLE_END_PROGRESS_BACKGROUND, + false, progressBackgroundPaint); + } else { + float gapAngle = (float) (progressGap / maxProgressValue * 360); + + float startAngle = this.sweepAngle + this.startAngle + gapAngle; + float sweepAngle = 360 - this.sweepAngle - 2 * gapAngle; + + if (sweepAngle < 0) { + return; + } + + canvas.drawArc(circleBounds, startAngle, sweepAngle, + false, progressBackgroundPaint); + } } private void drawProgress(Canvas canvas) { @@ -403,34 +425,27 @@ public void setProgress(double current, double max) { if (isAnimationEnabled) { startProgressAnimation(oldCurrentProgress, finalAngle); } else { - sweepAngle = (int) finalAngle; + sweepAngle = (float) finalAngle; invalidate(); } } private void startProgressAnimation(double oldCurrentProgress, final double finalAngle) { - final PropertyValuesHolder angleProperty = PropertyValuesHolder.ofInt(PROPERTY_ANGLE, sweepAngle, (int) finalAngle); + final PropertyValuesHolder angleProperty = PropertyValuesHolder.ofFloat(PROPERTY_ANGLE, sweepAngle, (float) finalAngle); - progressAnimator = ValueAnimator.ofObject(new TypeEvaluator() { - @Override - public Double evaluate(float fraction, Double startValue, Double endValue) { - return (startValue + (endValue - startValue) * fraction); - } - }, oldCurrentProgress, progressValue); - progressAnimator.setDuration(DEFAULT_ANIMATION_DURATION); + progressAnimator = ValueAnimator.ofObject((TypeEvaluator) + (fraction, startValue, endValue) -> (startValue + (endValue - startValue) * fraction), oldCurrentProgress, progressValue); + progressAnimator.setDuration(animationDuration); progressAnimator.setValues(angleProperty); progressAnimator.setInterpolator(animationInterpolator); - progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - sweepAngle = (int) animation.getAnimatedValue(PROPERTY_ANGLE); - invalidate(); - } + progressAnimator.addUpdateListener(animation -> { + sweepAngle = (float) animation.getAnimatedValue(PROPERTY_ANGLE); + invalidate(); }); progressAnimator.addListener(new DefaultAnimatorListener() { @Override public void onAnimationCancel(Animator animation) { - sweepAngle = (int) finalAngle; + sweepAngle = (float) finalAngle; invalidate(); progressAnimator = null; } @@ -621,7 +636,6 @@ public float getDotWidth() { return dotPaint.getStrokeWidth(); } - public double getProgress() { return progressValue; } @@ -658,6 +672,7 @@ public void setProgressStrokeCap(@Cap int cap) { Paint.Cap paintCap = (cap == CAP_ROUND) ? Paint.Cap.ROUND : Paint.Cap.BUTT; if (progressPaint.getStrokeCap() != paintCap) { progressPaint.setStrokeCap(paintCap); + progressBackgroundPaint.setStrokeCap(paintCap); invalidate(); } } @@ -696,6 +711,24 @@ public boolean isFillBackgroundEnabled() { return isFillBackgroundEnabled; } + public void setShowTextEnabled(boolean enabled) { + if (isShowTextEnabled == enabled) return; + isShowTextEnabled = enabled; + invalidateEverything(); + } + + public boolean isShowTextEnabled() { + return isShowTextEnabled; + } + + public void setAnimationDuration(int duration) { + animationDuration = duration; + } + + public int getAnimationDuration() { + return animationDuration; + } + public void setInterpolator(@NonNull Interpolator interpolator) { animationInterpolator = interpolator; } @@ -706,23 +739,28 @@ public Interpolator getInterpolator() { } public void setGradient(@GradientType int type, @ColorInt int endColor) { + int startColor = progressPaint.getColor(); + setGradient(type, new int[]{startColor, endColor}, null); + } + + public void setGradient(@GradientType int type, @Size(min = 2) @ColorInt int[] colors, @Nullable float[] positions) { Shader gradient = null; float cx = getWidth() / 2f; float cy = getHeight() / 2f; - int startColor = progressPaint.getColor(); - switch (type) { case LINEAR_GRADIENT: - gradient = new LinearGradient(0f, 0f, getWidth(), getHeight(), startColor, endColor, Shader.TileMode.CLAMP); + gradient = new LinearGradient(0f, 0f, getWidth(), getHeight(), colors, positions, Shader.TileMode.CLAMP); break; case RADIAL_GRADIENT: - gradient = new RadialGradient(cx, cy, cx, startColor, endColor, Shader.TileMode.MIRROR); + gradient = new RadialGradient(cx, cy, cx, colors, positions, Shader.TileMode.MIRROR); break; case SWEEP_GRADIENT: - gradient = new SweepGradient(cx, cy, new int[]{startColor, endColor}, null); + gradient = new SweepGradient(cx, cy, colors, positions); break; + case NO_GRADIENT: + return; } if (gradient != null) { @@ -753,6 +791,15 @@ public int getGradientType() { return type; } + public double getProgressGap() { + return progressGap; + } + + public void setProgressGap(double progressGap) { + this.progressGap = progressGap; + invalidate(); + } + @Retention(RetentionPolicy.SOURCE) @IntDef({DIRECTION_CLOCKWISE, DIRECTION_COUNTERCLOCKWISE}) public @interface Direction { diff --git a/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/DefaultProgressTextAdapter.java b/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/DefaultProgressTextAdapter.java index acd8375..e515646 100644 --- a/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/DefaultProgressTextAdapter.java +++ b/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/DefaultProgressTextAdapter.java @@ -1,11 +1,14 @@ package antonkozyriatskyi.circularprogressindicator; +import androidx.annotation.NonNull; + /** * Created by Anton on 06.06.2018. */ public final class DefaultProgressTextAdapter implements CircularProgressIndicator.ProgressTextAdapter { + @NonNull @Override public String formatText(double currentProgress) { return String.valueOf((int) currentProgress); diff --git a/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/PatternProgressTextAdapter.java b/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/PatternProgressTextAdapter.java index 617344c..037a5d4 100644 --- a/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/PatternProgressTextAdapter.java +++ b/circularprogressindicator/src/main/java/antonkozyriatskyi/circularprogressindicator/PatternProgressTextAdapter.java @@ -1,6 +1,6 @@ package antonkozyriatskyi.circularprogressindicator; -import android.support.annotation.NonNull; +import androidx.annotation.NonNull; /** * Created by Anton on 06.06.2018. @@ -8,7 +8,7 @@ public final class PatternProgressTextAdapter implements CircularProgressIndicator.ProgressTextAdapter { - private String pattern; + private final String pattern; public PatternProgressTextAdapter(String pattern) { this.pattern = pattern; diff --git a/circularprogressindicator/src/main/res/values/attrs.xml b/circularprogressindicator/src/main/res/values/attrs.xml index 4a6986e..9622338 100644 --- a/circularprogressindicator/src/main/res/values/attrs.xml +++ b/circularprogressindicator/src/main/res/values/attrs.xml @@ -31,6 +31,7 @@ + @@ -42,4 +43,4 @@ - \ No newline at end of file + diff --git a/example/build.gradle b/example/build.gradle index 924b8a7..dac7527 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 + compileSdkVersion 31 defaultConfig { applicationId "antonkozyriatskyi.circularprogressindicatorexample" minSdkVersion 15 - targetSdkVersion 27 + targetSdkVersion 31 versionCode 1 versionName "1.0" } @@ -21,6 +21,6 @@ dependencies { implementation project(':circularprogressindicator') implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:appcompat-v7:27.1.0' - implementation 'com.android.support:design:27.1.0' + implementation 'androidx.appcompat:appcompat:1.4.1' + implementation 'com.google.android.material:material:1.5.0' } diff --git a/example/src/main/AndroidManifest.xml b/example/src/main/AndroidManifest.xml index 580474d..8e3b35b 100644 --- a/example/src/main/AndroidManifest.xml +++ b/example/src/main/AndroidManifest.xml @@ -10,7 +10,9 @@ android:supportsRtl="true" android:theme="@style/Theme.AppCompat.Light.NoActionBar"> - + diff --git a/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/ColorPickerDialogFragment.java b/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/ColorPickerDialogFragment.java index 8790663..7b6805d 100644 --- a/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/ColorPickerDialogFragment.java +++ b/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/ColorPickerDialogFragment.java @@ -4,15 +4,17 @@ import android.graphics.PorterDuff; import android.os.Build; import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.BottomSheetDialogFragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.SeekBar; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; + /** * Created by Anton on 13.03.2018. */ @@ -55,25 +57,22 @@ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { colorResult.setBackgroundColor(Color.rgb(redProgress, greenProgress, blueProgress)); - switch (seekBar.getId()) { - case R.id.sb_red: - seekBar.getProgressDrawable().setColorFilter(Color.rgb(redProgress, 0, 0), mode); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - seekBar.getThumb().setColorFilter(Color.rgb(redProgress, 0, 0), mode); - } - break; - case R.id.sb_green: - seekBar.getProgressDrawable().setColorFilter(Color.rgb(0, greenProgress, 0), mode); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - seekBar.getThumb().setColorFilter(Color.rgb(0, greenProgress, 0), mode); - } - break; - case R.id.sb_blue: - seekBar.getProgressDrawable().setColorFilter(Color.rgb(0, 0, blueProgress), mode); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { - seekBar.getThumb().setColorFilter(Color.rgb(0, 0, blueProgress), mode); - } - break; + int id = seekBar.getId(); + if (id == R.id.sb_red) { + seekBar.getProgressDrawable().setColorFilter(Color.rgb(redProgress, 0, 0), mode); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + seekBar.getThumb().setColorFilter(Color.rgb(redProgress, 0, 0), mode); + } + } else if (id == R.id.sb_green) { + seekBar.getProgressDrawable().setColorFilter(Color.rgb(0, greenProgress, 0), mode); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + seekBar.getThumb().setColorFilter(Color.rgb(0, greenProgress, 0), mode); + } + } else if (id == R.id.sb_blue) { + seekBar.getProgressDrawable().setColorFilter(Color.rgb(0, 0, blueProgress), mode); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + seekBar.getThumb().setColorFilter(Color.rgb(0, 0, blueProgress), mode); + } } } }; @@ -82,13 +81,10 @@ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { green.setOnSeekBarChangeListener(seekBarChangeListener); blue.setOnSeekBarChangeListener(seekBarChangeListener); - selectColor.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - onColorSelectedListener.onColorChosen(ColorPickerDialogFragment.this, - red.getProgress(), green.getProgress(), blue.getProgress()); - dismiss(); - } + selectColor.setOnClickListener(v -> { + onColorSelectedListener.onColorChosen(ColorPickerDialogFragment.this, + red.getProgress(), green.getProgress(), blue.getProgress()); + dismiss(); }); return rootView; diff --git a/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/MainActivity.java b/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/MainActivity.java index 84f7c97..8ec7548 100644 --- a/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/MainActivity.java +++ b/example/src/main/java/antonkozyriatskyi/circularprogressindicatorexample/MainActivity.java @@ -2,18 +2,18 @@ import android.graphics.Color; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.AdapterView; import android.widget.Button; import android.widget.CheckBox; -import android.widget.CompoundButton; import android.widget.RadioGroup; import android.widget.SeekBar; import android.widget.SimpleAdapter; import android.widget.Spinner; -import android.widget.Switch; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.SwitchCompat; import java.util.ArrayList; import java.util.HashMap; @@ -26,6 +26,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe private Button dotColor; private SeekBar dotWidth; + private SeekBar gapSize; private CircularProgressIndicator circularProgress; @@ -52,66 +53,44 @@ protected void onCreate(Bundle savedInstanceState) { final SeekBar progressBackgroundStrokeWidth = findViewById(R.id.sb_progress_background_width); SeekBar textSize = findViewById(R.id.sb_text_size); dotWidth = findViewById(R.id.sb_dot_width); + gapSize = findViewById(R.id.sb_gap_size); progress.setOnSeekBarChangeListener(this); progressStrokeWidth.setOnSeekBarChangeListener(this); progressBackgroundStrokeWidth.setOnSeekBarChangeListener(this); textSize.setOnSeekBarChangeListener(this); dotWidth.setOnSeekBarChangeListener(this); + gapSize.setOnSeekBarChangeListener(this); CheckBox drawDot = findViewById(R.id.cb_draw_dot); - drawDot.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - circularProgress.setShouldDrawDot(isChecked); - dotWidth.setEnabled(isChecked); - dotColor.setEnabled(isChecked); - } + drawDot.setOnCheckedChangeListener((buttonView, isChecked) -> { + circularProgress.setShouldDrawDot(isChecked); + dotWidth.setEnabled(isChecked); + dotColor.setEnabled(isChecked); }); CheckBox useCustomTextAdapter = findViewById(R.id.cb_custom_text_adapter); - useCustomTextAdapter.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - circularProgress.setProgressTextAdapter(isChecked ? TIME_TEXT_ADAPTER : null); - } - }); + useCustomTextAdapter.setOnCheckedChangeListener((buttonView, isChecked) -> circularProgress.setProgressTextAdapter(isChecked ? TIME_TEXT_ADAPTER : null)); CheckBox fillBackground = findViewById(R.id.cb_fill_background); - fillBackground.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - circularProgress.setFillBackgroundEnabled(isChecked); - } - }); + fillBackground.setChecked(circularProgress.isFillBackgroundEnabled()); + fillBackground.setOnCheckedChangeListener((buttonView, isChecked) -> circularProgress.setFillBackgroundEnabled(isChecked)); + + CheckBox showText = findViewById(R.id.cb_show_text); + showText.setChecked(circularProgress.isShowTextEnabled()); + showText.setOnCheckedChangeListener((buttonView, isChecked) -> circularProgress.setShowTextEnabled(isChecked)); RadioGroup progressCap = findViewById(R.id.rg_cap); - progressCap.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(RadioGroup group, int checkedId) { - switch (checkedId) { - case R.id.rb_cap_butt: - circularProgress.setProgressStrokeCap(CircularProgressIndicator.CAP_BUTT); - break; - case R.id.rb_cap_round: - circularProgress.setProgressStrokeCap(CircularProgressIndicator.CAP_ROUND); - break; - } + progressCap.setOnCheckedChangeListener((group, checkedId) -> { + if (checkedId == R.id.rb_cap_butt) { + circularProgress.setProgressStrokeCap(CircularProgressIndicator.CAP_BUTT); + } else if (checkedId == R.id.rb_cap_round) { + circularProgress.setProgressStrokeCap(CircularProgressIndicator.CAP_ROUND); } }); - circularProgress.setOnProgressChangeListener(new CircularProgressIndicator.OnProgressChangeListener() { - @Override - public void onProgressChanged(double progress, double maxProgress) { - Log.d("PROGRESS", String.format("Current: %1$.0f, max: %2$.0f", progress, maxProgress)); - } - }); + circularProgress.setOnProgressChangeListener((progress1, maxProgress) -> Log.d("PROGRESS", String.format("Current: %1$.0f, max: %2$.0f", progress1, maxProgress))); - Switch animationSwitch = findViewById(R.id.sw_enable_animation); - animationSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - circularProgress.setAnimationEnabled(isChecked); - } - }); + SwitchCompat animationSwitch = findViewById(R.id.sw_enable_animation); + animationSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> circularProgress.setAnimationEnabled(isChecked)); Spinner gradientType = findViewById(R.id.sp_gradient_type); @@ -136,7 +115,6 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { gradient.put("value", "3"); gradients.add(gradient); - gradientType.setAdapter( new SimpleAdapter( this, @@ -163,19 +141,15 @@ public void onClick(View v) { ColorPickerDialogFragment dialog = new ColorPickerDialogFragment(); dialog.setOnColorSelectedListener(this); String tag = null; - switch (v.getId()) { - case R.id.btn_progress_color: - tag = "progressColor"; - break; - case R.id.btn_background_color: - tag = "progressBackgroundColor"; - break; - case R.id.btn_text_color: - tag = "textColor"; - break; - case R.id.btn_dot_color: - tag = "dotColor"; - break; + int id = v.getId(); + if (id == R.id.btn_progress_color) { + tag = "progressColor"; + } else if (id == R.id.btn_background_color) { + tag = "progressBackgroundColor"; + } else if (id == R.id.btn_text_color) { + tag = "textColor"; + } else if (id == R.id.btn_dot_color) { + tag = "dotColor"; } dialog.show(getSupportFragmentManager(), tag); @@ -183,22 +157,19 @@ public void onClick(View v) { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { - switch (seekBar.getId()) { - case R.id.sb_progress: - circularProgress.setCurrentProgress(progress); - break; - case R.id.sb_progress_width: - circularProgress.setProgressStrokeWidthDp(progress); - break; - case R.id.sb_dot_width: - circularProgress.setDotWidthDp(progress); - break; - case R.id.sb_text_size: - circularProgress.setTextSizeSp(progress); - break; - case R.id.sb_progress_background_width: - circularProgress.setProgressBackgroundStrokeWidthDp(progress); - break; + int id = seekBar.getId(); + if (id == R.id.sb_progress) { + circularProgress.setCurrentProgress(progress); + } else if (id == R.id.sb_progress_width) { + circularProgress.setProgressStrokeWidthDp(progress); + } else if (id == R.id.sb_dot_width) { + circularProgress.setDotWidthDp(progress); + } else if (id == R.id.sb_text_size) { + circularProgress.setTextSizeSp(progress); + } else if (id == R.id.sb_progress_background_width) { + circularProgress.setProgressBackgroundStrokeWidthDp(progress); + } else if (id == R.id.sb_gap_size) { + circularProgress.setProgressGap(progress * 10); } } @@ -233,27 +204,24 @@ public void onColorChosen(ColorPickerDialogFragment dialog, int r, int g, int b) } } - private static final CircularProgressIndicator.ProgressTextAdapter TIME_TEXT_ADAPTER = new CircularProgressIndicator.ProgressTextAdapter() { - @Override - public String formatText(double time) { - int hours = (int) (time / 3600); - time %= 3600; - int minutes = (int) (time / 60); - int seconds = (int) (time % 60); - StringBuilder sb = new StringBuilder(); - if (hours < 10) { - sb.append(0); - } - sb.append(hours).append(":"); - if (minutes < 10) { - sb.append(0); - } - sb.append(minutes).append(":"); - if (seconds < 10) { - sb.append(0); - } - sb.append(seconds); - return sb.toString(); + private static final CircularProgressIndicator.ProgressTextAdapter TIME_TEXT_ADAPTER = time -> { + int hours = (int) (time / 3600); + time %= 3600; + int minutes = (int) (time / 60); + int seconds = (int) (time % 60); + StringBuilder sb = new StringBuilder(); + if (hours < 10) { + sb.append(0); + } + sb.append(hours).append(":"); + if (minutes < 10) { + sb.append(0); + } + sb.append(minutes).append(":"); + if (seconds < 10) { + sb.append(0); } + sb.append(seconds); + return sb.toString(); }; } diff --git a/example/src/main/res/layout/activity_main.xml b/example/src/main/res/layout/activity_main.xml index e050f43..004dd00 100644 --- a/example/src/main/res/layout/activity_main.xml +++ b/example/src/main/res/layout/activity_main.xml @@ -5,15 +5,16 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - tools:context="antonkozyriatskyi.circularprogressindicatorexample.MainActivity"> + tools:context="antonkozyriatskyi.circularprogressindicatorexample.MainActivity" + tools:ignore="HardcodedText"> - @@ -101,6 +102,7 @@ android:id="@+id/cb_custom_text_adapter" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:text="Use custom text adapter (HH:MM:SS)" /> @@ -108,9 +110,18 @@ android:id="@+id/cb_fill_background" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginStart="8dp" android:layout_marginLeft="8dp" android:text="Fill background" /> + + + + + + - + android:layout_height="wrap_content" />