Пользовательский вид drawArc, обнаружение касания пользователя на пути рисования дуги

Я создаю пользовательский вид, который является своего рода представлением прогресса ползунка. Я могу рисовать больше или меньше дуги, основанной на том, где пользователь прикасается (по оси x), вычисляя развертку, я делаю это сначала вычисление персетажа, где пользователь коснулся оси x..0% было бы полностью влево, а 100% было бы полностью направо.

Я хочу сделать это еще дальше, вместо того, чтобы рисовать дугу на основе координаты x, которую пользователь нажимает, я хочу заставить ее двигаться только тогда, когда пользователь коснется фактического пути рисования дуги, поэтому он более реалистичен. Я по-прежнему новичок в пользовательских представлениях, и моя математика ограничена, но если я получу несколько советов, я был бы благодарен спасибо

how it looks when user moves there finger on the area of the rectangle as a percentage along the x axis

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;
    }
}

Ответ 1

Это работает для вас? Вам не нужно много математики. Вы можете рассчитать расстояние от точки касания от центра вашей дуги (это кружок так легко) и сравнить это с радиусом, который вы используете. Это скажет вам, находится ли точка на дуге (почти, см. Ниже полный случай).

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 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 

}

Ответ 2

Я хочу заставить его двигаться только тогда, когда пользователь коснется фактической дуги рисовать путь

В начале onTouchEvent() вам нужно проверить, выполняются ли какие-либо условия xPosition и yPosition. Если да, вы делаете то, что делаете сейчас. Если нет, return true.

Состояние:

Мы хотим проверить, находятся ли x, y в этом фоне серой дуги:

enter image description here

Пусть вычисляется расстояние от (x, y) до этой точки (a, b) в центре:

final dist = distance(x, y, a, b)

distance() - простое евклидово расстояние между точками (x, y) и (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 находятся в этом фоне серой дуги, если y > Y && dist >= r && dist <= R.