在Android时钟中移动小时指针

6

我正在尝试编写一个简单的概念验证应用程序,允许用户旋转时钟的分钟针。 我很难想出正确的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

数学计算正确。您的计算应该可以给出触摸事件的角度,其中在中心点正右方的触摸应该给出0度。

需要注意以下几点:

  • 确保您正在正确旋转。这很难保持清晰,因此容易出错。
  • 确保您考虑到值为0意味着分针应指向右侧。例如,如果您开始时的分针指向上方,则需要在计算结果上添加/减去90度(取决于旋转方向-不确定哪个是正确的)。
  • 确保(cx,cy)是您要计算角度的中心点。
  • 在旋转时,您需要使用3个参数的 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();

谢谢。我会再次检查我的中心点。我认为问题在于中心点相对于整个屏幕而言,而不是时钟。所以它大约是240, 240。这可能是真正的问题。你有什么想法吗? - bek
@user968322 我已经添加了一些有关旋转中心的额外细节。 - JesusFreke
尝试了所有方法,仍然没有运气。它开始随机移动。我在我的帖子中更新了原始代码。 - bek

0
您的计算适用于测量模拟时钟中分针旋转到相应象限的角度...稍加更改即可使分钟或小时指针旋转到触摸位置...在onTouch()方法中调用下面的方法以进行移动操作。
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;
}

我有一个使用向量概念来计算角度的方法,但如果需要的话,我可以提供比你的代码更详细的逻辑。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接