Переместить Минутную стрелку в часах Android - PullRequest
6 голосов
/ 28 сентября 2011

Я пытаюсь написать простое приложение для проверки концепции, которое позволяет пользователю вращать минутную стрелку часов. Мне трудно придумать правильную логику для OnTouchEvent.

Пока у меня есть следующий код:

    public boolean onTouchEvent(MotionEvent e) {

       float x = e.getX();
       float y = e.getY();

    switch (e.getAction()) {
    case MotionEvent.ACTION_MOVE:
        //find an approximate angle between them.

        float dx = x-cx;
        float dy = y-cy;
        double a=Math.atan2(dy,dx);

        this.degree = Math.toDegrees(a);
        this.invalidate();
    }
    return true;
    }


protected void onDraw(Canvas canvas) {
    super .onDraw(canvas);

    boolean changed = mChanged;
    if (changed) {
        mChanged = false;
    }

    int availableWidth = getRight() - getLeft();
    int availableHeight = getBottom() - getTop();

    int x = availableWidth / 2;
    int y = availableHeight / 2;

    cx = x;
    cy = y;

    final Drawable dial = mDial;

    int w = dial.getIntrinsicWidth() + 100;
    int h = dial.getIntrinsicHeight() + 100;

    boolean scaled = false;

    if (availableWidth < w || availableHeight < h) {
        scaled = true;

        float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h);

        canvas.save();
        canvas.scale(scale, scale, x, y);
    }

    if (changed)
    {
        dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
    }

    dial.draw(canvas);

    canvas.save();
    float hour = mHour / 12.0f * 360.0f;

    canvas.rotate(hour, x, y);

    final Drawable hourHand = mHourHand;

    if (changed) {

        w = hourHand.getIntrinsicWidth() + 30;
        h = hourHand.getIntrinsicHeight() + 30;

        hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y  + (h / 2));
    }

    hourHand.draw(canvas);
    canvas.restore();

    canvas.save();
    float minute = mMinutes / 60.0f * 360.0f;

    if (bearing == 0)
    {
        canvas.rotate(minute, x, y);
    }
    else
    {
        canvas.rotate((float)bearing, x, y);
    }

    final Drawable minuteHand = mMinuteHand;

    if (changed) {

        w = minuteHand.getIntrinsicWidth() + 30;
        h = minuteHand.getIntrinsicHeight() + 30;

        minuteHand.setBounds(x - w, y - h, x + w, y  + h);
    }

    minuteHand.draw(canvas);
    canvas.restore();

    if (scaled) {
        canvas.restore();
    }
}

Затем, основываясь на этом, мой метод OnDraw вращает минутную стрелку до указанного «this.degree» (просто вызывает canvas.rotate). Я предполагаю, что моя математика здесь. Я попытался следовать примеру здесь: Рассчитать угол поворота в круговой диаграмме , но это все еще не правильно вращает минутную стрелку. Любая помощь будет оценена.

Ответы [ 2 ]

2 голосов
/ 28 сентября 2011

Математика выглядит правильно.Ваши расчеты должны дать вам угол события касания, когда касание, которое находится точно справа от центральной точки, должно дать вам 0 градусов.

Несколько вещей, на которые следует обратить внимание:

  • Убедитесь, что вы вращаетесь в правильном направлении.Трудно держать это прямо, и, следовательно, легко облажаться
  • Убедитесь, что вы принимаете во внимание, что значение 0 означает, что минутная стрелка должна указывать вправо.Например, если вы начинаете с минутной стрелки, которая направлена ​​вверх, вам нужно будет прибавить / вычесть 90 градусов к результату вашего расчета (в зависимости от направления вращения - не уверен, что это правильно) -
  • Убедитесь, что (cx, cy) - это центральная точка, вокруг которой вы хотите рассчитать угол
  • При вращении вам нужно будет либо использовать метод 3 arg Canvas.rotate(float, float, float), либо добавить дополнительныйперевод по отдельности, чтобы убедиться, что вы вращаетесь вокруг правильной точки.Без какого-либо перевода он будет вращаться вокруг (0,0) (верхний левый угол обзора)

Больше при вращении: вращение всегда происходит вокруг «текущей» (0,0) точки.Под «текущим» я подразумеваю точку (0,0) после применения текущей матрицы.Когда вы впервые вводите onDraw, точка (0,0) должна быть в верхнем левом углу представления.Всякий раз, когда вы применяете перевод / масштабирование / и т. Д., Вы потенциально можете изменить положение точки (0,0) относительно вида.

Я думаю, что что-то вроде следующего должно работать в отношении установки правильногоцентр вращения:

//first we save the initial matrix, so we can easily get
//back to this state after we're done rotating
canvas.save();
//I *think* you need to negate the center offsets here,
//because you are conceptually moving the canvas, rather
//than moving the center directly
canvas.translate(-cx, -cy);
//<perform the rotation and draw the clock hand>
//...

//and now restore the matrix back to the initial state   
canvas.restore();
0 голосов
/ 16 декабря 2013

Ваш расчет подходит для измерения угла для минутной стрелки вращаться в соответствующих квадрантах в аналоговых часах ... здесь с небольшим битовые изменения могут привести к вращению минутной или часовой стрелки на touch position .... вызов метода ниже в методе onTouch () для действия move

public float getRotationAngle(float x, float y) {
        float dx = x - cx;
        float dy = y - cy;
        double a = Math.atan2(dy, dx);

        double degree = Math.toDegrees(a)+90;
        if(angle<0){
            degree=degree+360;
        }
        return (float) degree;
}

У меня есть этот подход с концепцией векторов для вычисления угла, но если немного больше, чем ваш код, если хотите, я дам эту логику ....

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...