2011-09-28 35 views
5

我想写一个简单的概念验证应用程序,允许用户旋转时钟分针。我很难为OnTouchEvent提供正确的逻辑。在Android时钟移动分钟手

到目前为止,我有以下代码:

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)。我假设我的数学不在这里。我试图按照这里的例子:Calculate angle for rotation in Pie Chart,但这仍然没有正确旋转分针。任何帮助,将不胜感激。

回答

2

数学看起来正确。你的计算应该给你触摸事件的角度,触摸是在中心点的正确的右边应该给你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

谢谢。我会仔细检查我的中心点。我认为问题是中心点是相对于整个屏幕而不是时钟。所以它就像240,240一样。这可能是真正的问题。思考? – bek

+0

@ user968322我已经添加了一些关于旋转中心的更多细节 – JesusFreke

+0

尝试了所有,仍然没有运气。它开始移动到随机方向。更新了我的文章中的原始代码。 – 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; 
} 

我有这种方法与作为计算的角度向量的概念,但如果不是你的代码多一点,如果ü想我会给这个逻辑....