diff --git a/circularrangeslider/src/main/java/com/bikcrum/circularrangeslider/CircularRangeSlider.java b/circularrangeslider/src/main/java/com/bikcrum/circularrangeslider/CircularRangeSlider.java
index 9a2017d..65a1785 100644
--- a/circularrangeslider/src/main/java/com/bikcrum/circularrangeslider/CircularRangeSlider.java
+++ b/circularrangeslider/src/main/java/com/bikcrum/circularrangeslider/CircularRangeSlider.java
@@ -1,5 +1,6 @@
package com.bikcrum.circularrangeslider;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.TypedArray;
@@ -10,10 +11,11 @@
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.NonNull;
+
public class CircularRangeSlider extends View {
//attributes
private int max;
@@ -21,7 +23,9 @@ public class CircularRangeSlider extends View {
private CharSequence[] labels;
private int labelColor;
private float labelSize;
+ private int labelInterval;
private boolean hideLabel;
+ private boolean hideZero;
private int circleColor;
@@ -38,6 +42,8 @@ public class CircularRangeSlider extends View {
private int axisColor;
private int startFrom;
+ private float startAngle;
+ private float endAngle;
private float startIndexStepLength;
private float startIndexStepWidth;
@@ -46,19 +52,18 @@ public class CircularRangeSlider extends View {
private float progress;
private boolean progressEnabled;
private int progressColor;
+ private float progressLength;
private int startIndex;
private int endIndex;
- private boolean enabled;
-
//non user required
- private Paint paint = new Paint();
+ private final Paint paint = new Paint();
private float centerX;
private float centerY;
private float radius;
private float stepsGap;
- private RectF ovalBigArc = new RectF();
+ private final RectF ovalBigArc = new RectF();
private float startThumbCenterX;
private float endThumbCenterX;
private float endThumbCenterY;
@@ -68,18 +73,14 @@ public class CircularRangeSlider extends View {
private OnRangeChangeListener onRangeChangeListener = null;
private int startIndexOld = -1;
private int endIndexOld = -1;
- private int[] mTempStates = new int[2];
+ private final int[] mTempStates = new int[2];
private float transformAngle;
- private Rect bounds = new Rect();
+ private final Rect bounds = new Rect();
private final String TAG = "demo";
private int getCircleColor() {
- if (isEnabled()) {
- return circleColor;
- } else {
- return Color.parseColor("#eeeeee");
- }
+ return circleColor;
}
public void setAxisColor(int axisColor) {
@@ -94,7 +95,7 @@ public void setLabelVisibility(int visibility) {
}
- private class Gravity {
+ private static class Gravity {
private static final int TOP = 1;
private static final int BOTTOM = 3;
private static final int RIGHT = 2;
@@ -103,9 +104,7 @@ private class Gravity {
public interface OnRangeChangeListener {
void onRangePress(int startIndex, int endIndex);
-
void onRangeChange(int startIndex, int endIndex);
-
void onRangeRelease(int startIndex, int endIndex);
}
@@ -118,16 +117,13 @@ public void setOnRangeChangeListener(OnRangeChangeListener onRangeChangeListener
}
public void setProgress(float progress) {
- if (!isEnabled()) {
- return;
- }
this.progress = progress;
invalidate();
}
public CircularRangeSlider(Context context, AttributeSet attrs) {
super(context, attrs);
- init(context, attrs, 0);
+ init(context, attrs);
}
public void setMax(int max) {
@@ -135,7 +131,7 @@ public void setMax(int max) {
max = 3;
}
this.max = max;
- stepsGap = 360f / max;
+ stepsGap = (endAngle - startAngle) / max;
if (endIndex >= max) {
endIndex = max - 2;
@@ -147,6 +143,8 @@ public void setMax(int max) {
if (onRangeChangeListener != null) {
onRangeChangeListener.onRangeChange(startIndex, endIndex);
}
+ setStartIndex(startIndex);
+ setEndIndex(endIndex);
invalidate();
}
@@ -167,11 +165,7 @@ public void setCircleColor(int circleColor) {
}
private int getBorderColor() {
- if (isEnabled()) {
- return borderColor;
- } else {
- return Color.parseColor("#e2e2e2");
- }
+ return borderColor;
}
public void setBorderColor(int borderColor) {
@@ -180,11 +174,7 @@ public void setBorderColor(int borderColor) {
}
private int getSectorColor() {
- if (isEnabled()) {
- return sectorColor;
- } else {
- return Color.parseColor("#26797979");
- }
+ return sectorColor;
}
public void setSectorColor(int sectorColor) {
@@ -242,11 +232,7 @@ public void setStartIndexStepWidth(float startIndexStepWidth) {
}
private int getStartIndexStepColor() {
- if (isEnabled()) {
- return startIndexStepColor;
- } else {
- return Color.WHITE;
- }
+ return startIndexStepColor;
}
public void setStartIndexStepColor(int startIndexStepColor) {
@@ -263,11 +249,7 @@ public boolean isProgressEnabled() {
}
private int getProgressColor() {
- if (isEnabled()) {
- return progressColor;
- } else {
- return Color.WHITE;
- }
+ return progressColor;
}
private void setProgressColor(int progressColor) {
@@ -281,9 +263,10 @@ public int getStartIndex() {
}
public void setStartIndex(int startIndex) {
+ startIndex = Math.min(Math.max(startIndex, 0), max);
this.startIndex = startIndex;
- startThumbAngle = startIndex * stepsGap;
- endThumbAngle = endIndex * stepsGap;
+ startThumbAngle = startAngle + (startIndex * stepsGap);
+ endThumbAngle = startAngle + (endIndex * stepsGap);
invalidate();
}
@@ -292,12 +275,19 @@ public int getEndIndex() {
}
public void setEndIndex(int endIndex) {
+ endIndex = Math.min(Math.max(endIndex, 0), max);
this.endIndex = endIndex;
- startThumbAngle = startIndex * stepsGap;
- endThumbAngle = endIndex * stepsGap;
+ startThumbAngle = startAngle + (startIndex * stepsGap);
+ endThumbAngle = startAngle + (endIndex * stepsGap);
+ invalidate();
+ }
+ public int getLabelInterval() {
+ return labelInterval;
+ }
+ public void setLabelInterval(int labelInterval) {
+ this.labelInterval = labelInterval;
invalidate();
}
-
public void setLabelColor(int color) {
labelColor = color;
invalidate();
@@ -307,15 +297,17 @@ public int getMax() {
return max;
}
- private void init(Context context, AttributeSet attrs, int defStyleAttr) {
- TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularRangeSlider, defStyleAttr, 0);
+ private void init(Context context, AttributeSet attrs) {
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularRangeSlider, 0, 0);
max = a.getInteger(R.styleable.CircularRangeSlider_max, 12);
stepLength = a.getDimension(R.styleable.CircularRangeSlider_stepLength, 10);
labels = a.getTextArray(R.styleable.CircularRangeSlider_labels);
labelColor = a.getColor(R.styleable.CircularRangeSlider_labelColor, Color.parseColor("#ffff00"));
labelSize = a.getDimension(R.styleable.CircularRangeSlider_labelSize, 30);
+ labelInterval = a.getInteger(R.styleable.CircularRangeSlider_labelInterval, 1);
hideLabel = a.getBoolean(R.styleable.CircularRangeSlider_hideLabel, false);
+ hideZero = a.getBoolean(R.styleable.CircularRangeSlider_hideZero, false);
circleColor = a.getColor(R.styleable.CircularRangeSlider_circleColor, Color.parseColor("#4db6ac"));
@@ -333,19 +325,22 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
axisColor = a.getColor(R.styleable.CircularRangeSlider_axisColor, Color.WHITE);
startFrom = a.getInteger(R.styleable.CircularRangeSlider_startFrom, Gravity.TOP);
+ startAngle = a.getFloat(R.styleable.CircularRangeSlider_startAngle, 0f);
+ endAngle = a.getFloat(R.styleable.CircularRangeSlider_endAngle, 360f);
- startIndexStepLength = a.getDimension(R.styleable.CircularRangeSlider_startIndexStepLength, stepLength * 2);
+ startIndexStepLength = a.getDimension(R.styleable.CircularRangeSlider_startIndexStepLength, stepLength);
startIndexStepWidth = a.getDimension(R.styleable.CircularRangeSlider_startIndexStepWidth, borderWidth * 1.5f);
startIndexStepColor = a.getColor(R.styleable.CircularRangeSlider_startIndexStepColor, Color.WHITE);
progress = a.getFloat(R.styleable.CircularRangeSlider_progress, 0);
progressEnabled = a.getBoolean(R.styleable.CircularRangeSlider_progressEnabled, false);
- progressColor = a.getColor(R.styleable.CircularRangeSlider_progressColor, Color.parseColor("#d50000"));
+ progressColor = a.getColor(R.styleable.CircularRangeSlider_progressColor, Color.WHITE);
+ progressLength = a.getFloat(R.styleable.CircularRangeSlider_progressLength, 1);
startIndex = a.getInt(R.styleable.CircularRangeSlider_startIndex, 0);
endIndex = a.getInt(R.styleable.CircularRangeSlider_endIndex, 1);
- enabled = a.getBoolean(R.styleable.CircularRangeSlider_enabled, true);
+ boolean enabled = a.getBoolean(R.styleable.CircularRangeSlider_enabled, true);
setEnabled(enabled);
@@ -357,12 +352,9 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
endIndex = max - 1;
}
- stepsGap = 360f / max;
+ stepsGap = (endAngle - startAngle) / max;
switch (startFrom) {
- case Gravity.TOP:
- transformAngle = 270;
- break;
case Gravity.BOTTOM:
transformAngle = 90;
break;
@@ -377,8 +369,8 @@ private void init(Context context, AttributeSet attrs, int defStyleAttr) {
break;
}
- startThumbAngle = startIndex * stepsGap;
- endThumbAngle = endIndex * stepsGap;
+ startThumbAngle = startAngle + (startIndex * stepsGap);
+ endThumbAngle = startAngle + (endIndex * stepsGap);
a.recycle();
@@ -388,14 +380,7 @@ private Path generateStepsPath() {
Path path = new Path();
for (int i = 0; i < max; i++) {
- double angRad = Math.toRadians(i * stepsGap);/*
- if (i == 0) {
- paint.setColor(startIndexStepColor);
- paint.setStrokeWidth(startIndexStepWidth);
- } else {
- paint.setColor(stepColor);
- paint.setStrokeWidth(stepWidth);
- }*/
+ double angRad = Math.toRadians(startAngle + (i * stepsGap));
float startX = centerX + (float) (radius * Math.cos(angRad));
float startY = centerY + (float) (radius * Math.sin(angRad));
float stopX = centerX + (float) ((radius - (i == 0 ? startIndexStepLength : stepLength)) * Math.cos(angRad));
@@ -405,17 +390,13 @@ private Path generateStepsPath() {
path.moveTo(startX, startY);
path.lineTo(stopX, stopY);
- // String tmp = String.valueOf(i);
- // paint.getTextBounds(tmp, 0, tmp.length(), bounds);
-
- // canvas.drawText(tmp, stopX, stopY, paint);
}
return path;
}
@Override
- protected void onDraw(Canvas canvas) {
+ protected void onDraw(@NonNull Canvas canvas) {
super.onDraw(canvas);
canvas.rotate(transformAngle, centerX, centerY);
paint.setStrokeCap(Paint.Cap.ROUND);
@@ -428,12 +409,28 @@ protected void onDraw(Canvas canvas) {
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(centerX, centerY, radius, paint);
+ //sector
+ float sweepAngle;
+ if (startThumbAngle >= endThumbAngle) {
+ sweepAngle = 360 - startThumbAngle + endThumbAngle;
+ } else {
+ sweepAngle = endThumbAngle - startThumbAngle;
+ }
+
+ paint.setColor(getSectorColor());
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawArc(ovalBigArc,
+ startThumbAngle,
+ sweepAngle,
+ true,
+ paint);
+
//steps
paint.setColor(getBorderColor());
paint.setStrokeWidth(borderWidth);
paint.setStyle(Paint.Style.FILL);
- for (int i = 0; i < max; i++) {
- double angRad = Math.toRadians(i * stepsGap);
+ for (int i = 0; i <= max; i++) {
+ double angRad = Math.toRadians(startAngle + (i * stepsGap));
if (i == 0) {
paint.setColor(getStartIndexStepColor());
paint.setStrokeWidth(startIndexStepWidth);
@@ -448,7 +445,11 @@ protected void onDraw(Canvas canvas) {
canvas.drawLine(startX, startY, stopX, stopY, paint);
//labels
- if (!hideLabel) {
+ boolean drawLabel = (i % labelInterval == 0);
+ drawLabel &= !((i == 0) && hideZero);
+ drawLabel &= !hideLabel;
+
+ if (drawLabel) {
String label;
if (labels != null) {
@@ -476,7 +477,7 @@ protected void onDraw(Canvas canvas) {
int x = (int) (centerX + Math.cos(angRad + Math.toRadians(transformAngle)) * (radius - padding - boundRadius));
int y = (int) (centerY + Math.sin(angRad + Math.toRadians(transformAngle)) * (radius - padding - boundRadius));
canvas.rotate(-transformAngle, centerX, centerY);
- canvas.drawText(label, x - bounds.width() / 2, y + bounds.height() / 2, paint);
+ canvas.drawText(label, x - (float) bounds.width() / 2, y + (float) bounds.height() / 2, paint);
canvas.rotate(transformAngle, centerX, centerY);
}
}
@@ -487,35 +488,6 @@ protected void onDraw(Canvas canvas) {
paint.setStrokeWidth(borderWidth);
canvas.drawCircle(centerX, centerY, radius, paint);
- //progress
- paint.setStyle(Paint.Style.FILL);
- if (progressEnabled && isEnabled()) {
- float angRad = (float) Math.toRadians(progress * stepsGap);
- float startX = centerX + (float) ((radius + borderWidth / 2) * Math.cos(angRad));
- float startY = centerY + (float) ((radius + borderWidth / 2) * Math.sin(angRad));
- float stopX = centerX + (float) ((radius - stepLength) * Math.cos(angRad));
- float stopY = centerY + (float) ((radius - stepLength) * Math.sin(angRad));
- paint.setColor(getProgressColor());
- paint.setStrokeWidth(borderWidth);
- canvas.drawLine(startX, startY, stopX, stopY, paint);
- }
-
- //sector
- float sweepAngle;
- if (startThumbAngle >= endThumbAngle) {
- sweepAngle = 360 - startThumbAngle + endThumbAngle;
- } else {
- sweepAngle = endThumbAngle - startThumbAngle;
- }
-
- paint.setColor(getSectorColor());
- paint.setStyle(Paint.Style.FILL);
- canvas.drawArc(ovalBigArc,
- startThumbAngle,
- sweepAngle,
- true,
- paint);
-
//start thumb
float cosineOfStartThumbAngle = (float) Math.cos(Math.toRadians(startThumbAngle));
float sineOfStartThumbAngle = (float) Math.sin(Math.toRadians(startThumbAngle));
@@ -550,6 +522,17 @@ protected void onDraw(Canvas canvas) {
paint);
+ //progress
+ paint.setStyle(Paint.Style.FILL);
+ if (progressEnabled) {
+ float angRad = (float) Math.toRadians(startAngle + (progress * stepsGap));
+ float stopX = centerX + (float) ((radius * progressLength) * Math.cos(angRad));
+ float stopY = centerY + (float) ((radius * progressLength) * Math.sin(angRad));
+ paint.setColor(getProgressColor());
+ paint.setStrokeWidth(sliderWidth);
+ canvas.drawLine(centerX, centerY, stopX, stopY, paint);
+ }
+
//center axis
paint.setColor(getAxisColor());
paint.setStyle(Paint.Style.FILL);
@@ -557,16 +540,13 @@ protected void onDraw(Canvas canvas) {
}
private int getAxisColor() {
- if (isEnabled()) {
- return axisColor;
- } else {
- return Color.parseColor("#ffffff");
- }
+ return axisColor;
}
private boolean touchedOnStartThumb;
private boolean touchedOnEndThumb;
+ @SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
if (!isEnabled()) {
@@ -630,8 +610,52 @@ private void moveThumb(float x, float y) {
} else if (touchedOnEndThumb) {
endThumbAngle = getNearestAngle(x, y);
}
- startIndex = (int) (startThumbAngle / stepsGap);
- endIndex = (int) (endThumbAngle / stepsGap);
+ int maxIndex = Math.round((endAngle - startAngle) / stepsGap);
+ startIndex = Math.round((startThumbAngle - startAngle) / stepsGap);
+ endIndex = Math.round((endThumbAngle - startAngle) / stepsGap);
+
+ if (startIndex >= endIndex)
+ {
+ if (touchedOnStartThumb)
+ {
+ if (endIndex < maxIndex)
+ {
+ endIndex = startIndex + 1;
+ endThumbAngle = startAngle + (endIndex * stepsGap);
+ }
+ else
+ {
+ startIndex = endIndex - 1;
+ startThumbAngle = startAngle + (startIndex * stepsGap);
+ }
+ }
+ else if (touchedOnEndThumb)
+ {
+ if (startIndex > 0)
+ {
+ startIndex = endIndex - 1;
+ startThumbAngle = startAngle + (startIndex * stepsGap);
+ }
+ else
+ {
+ endIndex = startIndex + 1;
+ endThumbAngle = startAngle + (endIndex * stepsGap);
+ }
+ }
+ }
+
+ if ((startIndex < 0))
+ {
+ startIndex = 0;
+ startThumbAngle = startAngle;
+ }
+
+ if (endIndex > maxIndex)
+ {
+ endIndex = maxIndex;
+ endThumbAngle = endAngle;
+ }
+
if (startIndex != startIndexOld || endIndex != endIndexOld) {
if (onRangeChangeListener != null) {
onRangeChangeListener.onRangeChange(startIndex, endIndex);
@@ -643,9 +667,11 @@ private void moveThumb(float x, float y) {
private float getNearestAngle(float x, float y) {
- float angle = (float) (Math.toDegrees(Math.atan2(y - centerY, x - centerX)));
- float angleCeil = ((int) Math.ceil(angle / stepsGap)) * stepsGap;
- float angleFloor = ((int) Math.floor(angle / stepsGap)) * stepsGap;
+ float angle = (float)(Math.toDegrees(Math.atan2(y - centerY, x - centerX)));
+ if (angle < 0) angle += 360;
+
+ float angleCeil = ((float)Math.ceil((angle - startAngle) / stepsGap) * stepsGap) + startAngle;
+ float angleFloor = ((float)Math.floor((angle - startAngle) / stepsGap) * stepsGap) + startAngle;
if (Math.abs(angle - angleCeil) < Math.abs(angle - angleFloor)) {
return angleCeil < 0 ? angleCeil + 360 : angleCeil;
@@ -666,12 +692,12 @@ private double distance(float x1, float y1, float x2, float y2) {
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (w < h) {
- radius = w / 2;
+ radius = (float) w / 2;
centerX = radius;
- centerY = h / 2;
+ centerY = (float) h / 2;
} else {
- radius = h / 2;
- centerX = w / 2;
+ radius = (float) h / 2;
+ centerX = (float) w / 2;
centerY = radius;
}
ovalBigArc.set(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
@@ -681,50 +707,46 @@ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
}
void debug(String[] names, String... values) {
- String a = "";
+ StringBuilder a = new StringBuilder();
for (int i = 0; i < names.length; i++) {
if (i != 0) {
- a += "\n";
+ a.append("\n");
}
- a += names[i] + " = " + values[i];
+ a.append(names[i]).append(" = ").append(values[i]);
}
// Log.i(TAG, a);
}
void debug(String[] names, Integer... values) {
- String a = "";
+ StringBuilder a = new StringBuilder();
for (int i = 0; i < names.length; i++) {
if (i != 0) {
- a += "\n";
+ a.append("\n");
}
- a += names[i] + " = " + values[i];
+ a.append(names[i]).append(" = ").append(values[i]);
}
// Log.i(TAG, a);
}
void debug(String[] names, Float... values) {
- String a = "";
+ StringBuilder a = new StringBuilder();
for (int i = 0; i < names.length; i++) {
if (i != 0) {
- a += "\n";
+ a.append("\n");
}
- a += names[i] + " = " + values[i];
+ a.append(names[i]).append(" = ").append(values[i]);
}
// Log.i(TAG, a);
}
private int getSliderColor(boolean pressed) {
if (sliderColor == null) {
- if (isEnabled()) {
- if (pressed) {
- return Color.parseColor("#e3fae6ab");
- }
- return Color.parseColor("#e3ffca28");
- } else {
- return Color.parseColor("#eeeeee");
+ if (pressed) {
+ return Color.parseColor("#e3fae6ab");
}
+ return Color.parseColor("#e3ffca28");
} else {
- mTempStates[0] = isEnabled() ? android.R.attr.state_enabled : -android.R.attr.state_enabled;
+ mTempStates[0] = android.R.attr.state_enabled;
mTempStates[1] = pressed ? android.R.attr.state_pressed : -android.R.attr.state_pressed;
return sliderColor.getColorForState(mTempStates, 0);
}
@@ -743,10 +765,7 @@ public boolean isProgressInsideRange() {
return progress >= startIndex && progress < endIndex;
} else if (startIndex > endIndex) {
return progress >= startIndex || progress < endIndex;
- } else if (startIndex == endIndex) {
- return true;
- }
- return false;
+ } else return true;
}
@@ -782,7 +801,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
- height = Math.min(desiredHeight, heightSize);
+ height = desiredHeight;
} else {
//Be whatever you want
height = desiredHeight;
diff --git a/circularrangeslider/src/main/res/values/attrs.xml b/circularrangeslider/src/main/res/values/attrs.xml
index f9adcd5..15e1cea 100644
--- a/circularrangeslider/src/main/res/values/attrs.xml
+++ b/circularrangeslider/src/main/res/values/attrs.xml
@@ -8,7 +8,9 @@
+
+
@@ -30,6 +32,8 @@
+
+
@@ -38,6 +42,7 @@
+