I am currently working on a custom Seekbar class called "ArcSlider" and I'm facing an issue with the arc direction. I want to draw an arc that opens upward, but I'm not very good at math, and I can only get it to open downward.
I have tried to adjust the sweepAngle and startAngle parameters, but when I do that, the view doesn't display the Seekbar anymore. I'm not interested in customizing the Seekbar shape from XML, I want to build this class programmatically.
Can anyone help me with the math required to draw an upward arc? Any tips or guidance would be greatly appreciated. Here is my code so far:
package com.am.app.amplayer.archslider;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import androidx.core.content.ContextCompat;
import com.am.app.amplayer.R;
import android.content.Context;
import android.widget.SeekBar;
import com.am.app.amplayer.helper.AppHelper;
import static java.lang.Math.*;
public class ArchSlider extends View {
/**
* value : progress of slider
* max : max value of slider
*/
private int value;
private int max;
// thumb
private final Drawable thumb;
// slider thikness
private float thikness;
/**
* track & progress properties
*/
private Paint track;
private Paint progress;
private int color;
private int trackColor;
// slider rect
private RectF rect;
// slider properties
private float radius;
private float centerX, centerY;
private float alphaRad;
public ArchSlider(Context context) {
this(context, null);
}
public ArchSlider(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ArchSlider(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle, R.style.archSliderStyle);
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ArchSlider, defStyle,
R.style.archSliderStyle);
value = array.getInt(R.styleable.ArchSlider_value, 14);
max = array.getInt(R.styleable.ArchSlider_max, 100);
color = array.getColor(R.styleable.ArchSlider_color, AppHelper.getColor(R.attr.colorPrimary));
trackColor = array.getColor(R.styleable.ArchSlider_trackColor, AppHelper.getColor(R.attr.colorSurfaceVariant));
thikness = array.getDimension(R.styleable.ArchSlider_thikness, getDisplayMetrics().density * 6);
array.recycle();
thumb = ContextCompat.getDrawable(context, R.drawable.arch_slider_thumb);
track = getPaint(trackColor);
progress = getPaint(color);
}
@Override
protected void onMeasure(int w, int h) {
float padding = max(thumb.getIntrinsicHeight() / 2.0f, thikness) + 2;
float width = View.getDefaultSize(getSuggestedMinimumWidth(), w) - 2 * padding - getPaddingStart()
- getPaddingEnd();
float height = min(View.getDefaultSize(getSuggestedMinimumHeight(), h) - 2 * padding - getPaddingTop()
- getPaddingBottom(), width / 2);
float maxPaddingX = max(getPaddingStart(), getPaddingEnd());
float maxPaddingY = max(getPaddingTop(), getPaddingBottom());
this.radius = (height / 2) + ((float) pow(width, 2.0) / (8 * height));
this.centerX = width / 2 + (padding + maxPaddingY);
this.centerY = radius + (padding + maxPaddingX);
this.rect = new RectF(centerX - radius, centerY - radius, radius + centerX, centerY + radius);
this.alphaRad = bound(0, (float) (acos((radius - height) / radius)), (float) (2 * PI));
super.onMeasure(w, h);
}
@Override
protected void onDraw(Canvas canvas) {
float startAngle = bound(180f, (float)(270-alphaRad/2/PI*360), 360f);
float sweepAngle = bound(0, (float)((2*alphaRad)/2/PI*360), 180f);
float progressSweepRad = max == 0 ? 0.0f : bound(0.0f,((float)value / (float)max * 2 * alphaRad), (float)(2f * PI));
float progressSweepAngle = progressSweepRad / 2.0f / (float)PI * 360.0f;
canvas.drawArc(rect, startAngle, sweepAngle, false, track);
canvas.drawArc(rect, startAngle, progressSweepAngle, false, progress);
AppHelper.toast("max:\t" + max + ",\tvalue:\t" + value, 1);
}
private DisplayMetrics getDisplayMetrics() {
return getResources().getDisplayMetrics();
}
private Paint getPaint(int color) {
Paint paint = new Paint();
paint.setColor(color);
paint.setStrokeWidth(thikness);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setAntiAlias(true);
return paint;
}
private final Float bound(float min, float value, float max) {
return max(min, min(value, max));
}
}
Thank you in advance for your help!
I have tried to adjust the sweepAngle and startAngle parameters,
float startAngle = bound(0f, (float) (90 - alphaRad / 2 / PI * 360), 180f);
float sweepAngle = bound(0, (float) ((2 * alphaRad) / 2 / PI * 360), 180f);
float progressSweepRad = max == 0 ? 0.0f : bound(0.0f, ((float) value / (float) max * 2 * alphaRad), (float) (2f * PI));
float progressSweepAngle = progressSweepRad / 2.0f / (float) PI * 360.0f;
canvas.drawArc(rect, startAngle, sweepAngle, false, track);
canvas.drawArc(rect, startAngle, progressSweepAngle, false, progress);
but i get empty view