2011-09-28 4 views
5

Estoy tratando de escribir una aplicación de prueba de concepto simple que le permita al usuario girar el minutero de un reloj. Tengo problemas para encontrar la lógica correcta para OnTouchEvent.Mueva la manecilla de los minutos en el reloj de Android

Hasta ahora tengo el siguiente código:

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

A continuación, basándose en eso, mi método OnDraw hace girar la manecilla de los minutos a la especificada "this.degree" (solo llamadas canvas.rotate). Estoy asumiendo que mi matemática está fuera de aquí. Traté de seguir el ejemplo aquí: Calculate angle for rotation in Pie Chart, pero eso aún no está rotando la manecilla de los minutos correctamente. Cualquier ayuda sería apreciada.

Respuesta

2

La matemática parece correcta. Tus cálculos deberían darte el ángulo del evento táctil, donde un toque que esté a la derecha exacta del punto central debería darte 0 grados.

Un par de cosas a tener en cuenta

  • Asegúrese de que está girando en la dirección correcta. Es difícil mantener esto en línea y, por lo tanto, es fácil arruinarlo
  • Asegúrese de tener en cuenta que un valor de 0 significa que el minutero debe estar apuntando hacia la derecha. Por ejemplo, si comienza con un minutero que apunta hacia arriba, debe sumar/restar 90 grados al resultado de su cálculo (dependiendo del sentido de rotación - no estoy seguro de cuál es el correcto al revés)
  • Hacer asegúrese de que (cx, cy) es el punto central alrededor del cual desea calcular el ángulo
  • Al girar, necesitará usar el método 3 arg Canvas.rotate(float, float, float), o agregar una traducción adicional por separado, para asegurarse de que están girando alrededor del punto correcto. Sin ningún tipo de traducción, que girará en torno a (0,0) (la esquina izquierda superior de la vista)

Más de rotación: Rotación siempre sucede alrededor del punto (0,0) "actual". Por "actual", me refiero al (0,0) punto después de que se haya aplicado la matriz actual. Cuando ingresa onDraw por primera vez, el punto (0,0) debe ser la esquina superior izquierda de la vista. Siempre que aplique una traducción/escalado/etc., posiblemente cambie dónde está el punto (0,0), en relación con la vista.

creo que algo como lo siguiente debería funcionar, en lo que respecta a la creación del centro de giro correcto:

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

Gracias. Volveré a verificar mi punto central. Creo que el problema es que el punto central es relativo a toda la pantalla, no al reloj. así que es algo así como 240, 240. Ese podría ser el verdadero problema. ¿Pensamientos? – bek

+0

@ user968322 He agregado algunos detalles adicionales con respecto al centro de rotación – JesusFreke

+0

intenté todo, aún no tuve suerte. Comienza a moverse hacia direcciones aleatorias. actualicé el código original en mi publicación. – bek

0

Su cálculo es buena para medir el ángulo de minutos la mano para giran en cuadrantes en analógica correspondiente reloj ... aquí con poco cambios de bit pueden hacer minutos u horas para girar en la posición táctil ... llamar al método siguiente en el método onTouch() para la acción mover

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

que tengo con este enfoque como vectores concepto para calcular el ángulo, pero si poco más de su código si quieres daré que la lógica ....

Cuestiones relacionadas