I am creating a custom view which is a kind of arc slider progress view.I can draw more or less of the arc based on where the user touches(on the x axis) by calculating the sweep, i do this by first calculating the percetage where the user touched along the x axis..0% would be all the way to the left and 100% would be all the way to the right.
I want to take this a step further, instead off drawing the arc based on the x coordinate that the user presses, I want to make it move only when the user touches on the actual arc draw path, so its more realistic. I am still new to custom views and my maths is limited but if I get some tips I would be grateful thanks
class ArcProgress extends View {
Context cx;
float width;
float height;
float center_x, center_y;
final RectF oval = new RectF();
final RectF touchArea = new RectF();
float sweep = 0;
float left, right;
int percent = 0;
public ArcProgress(Context context) {
super(context);
cx = context;
}
public int getPercentage() {
return percent;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
setBackgroundColor(0xfff0ebde);
width = (float) getWidth();
height = (float) getHeight();
float radius;
if (width > height) {
radius = height / 3;
} else {
radius = width / 3;
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(0xffd2c8b6);
paint.setStrokeWidth(35);
paint.setStyle(Paint.Style.STROKE);
center_x = width / 2;
center_y = height / 2;
left = center_x - radius;
float top = center_y - radius;
right = center_x + radius;
float bottom = center_y + radius;
oval.set(left, top, right, bottom);
//this is the background arc, it remains constant
canvas.drawArc(oval, 180, 180, false, paint);
paint.setStrokeWidth(10);
paint.setColor(0xffe0524d);
//this is the red arc whichhas its sweep argument manipulated by on touch
canvas.drawArc(oval, 180, sweep, false, paint);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE) {
float xPosition = event.getX();
float yPosition = event.getY();
if (oval.contains(xPosition, yPosition)) {
float x = xPosition - left;
float s = x * 100;
float b = s / oval.width();
percent = Math.round(b);
sweep = (180 / 100.0f) * (float) percent;
invalidate();
} else {
if (xPosition < left) {
percent = 0;
sweep = (180 / 100.0f) * (float) percent;
invalidate();
}
if (xPosition > right) {
percent = 100;
sweep = (180 / 100.0f) * (float) percent;
invalidate();
}
}
}
return true;
}
}
I want to make it move only when the user touches on the actual arc draw path
At the beginning of onTouchEvent()
you need to check whether xPosition
and yPosition
are fulfilling some condition. If yes, you do the stuff, which you are doing now. If no, return true
.
Condition:
We want to check whether x, y are in that grey arc background:
Let's calculate a distance from (x, y) to that point (a, b) in the center:
final dist = distance(x, y, a, b)
distance()
is a simple Euclidean distance between points (x,y) and (a,b):
double distance(int x, int y, int a, int b)
{
return Math.sqrt((x - a) * (x - a) + (y - b) * (y - b));
}
x, y are in that grey arc background, if y > Y && dist >= r && dist <= R
.
Does this work for you? You don't need a lot of Maths. You can calculate the distance of the touch point from the center of your arc (it's a circle so it's easy) and the compare that with the radius you are using. That will tell you if the point is on the arc (almost, see below for full case).
Point touchEv = ...;
Point circleCenter = ...;
//the radius of the circle you used to draw the arc
float circleRadius = ...;
//how far from the arc should a touch point treated as it's on the arc
float maxDiff = getResources().getDimension(R.dimen.max_diff_dp);
//calculate the distance of the touch point from the center of your circle
float dist = Math.pow(touchEv.x-circleCenter.x,2) + Math.pow(touchEv.y- circleCenter.y,2)
dist = Math.sqrt(dist);
//We also need the bounding rect of the top half of the circle (the visible arc)
Rect topBoundingRect = new Rect(circleCenter.x - circleRadius,
circleCenter.y - circleRadius,
circleCenter.x + circleRadius,
circleCenter.y);
if (Math.abs(dist - circleRadius) <= maxDiff &&
topBoundingRect.contains(touchEv.x, touchEv.y)) {
// the user is touching the arc
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With