2015-11-17 14 views
22

Ho fatto una manopola rotante, ma voglio fermare la manopola ad angoli specifici per 2 secondi. Voglio fermarlo su 260f e -20f.Come mettere in pausa la tela dalla rotazione per 2 secondi ad angoli specifici?

Qualcuno può suggerire come farlo?

Questo è il codice di un blog. Ho apportato molte modifiche in base alle mie esigenze.

public class RotatoryKnobView extends ImageView { 

    private float angle = -20f; 
    private float theta_old=0f; 

    private RotaryKnobListener listener; 

    public interface RotaryKnobListener { 
    public void onKnobChanged(float arg); 
    } 

    public void setKnobListener(RotaryKnobListener l) 
    { 
    listener = l; 
    } 

    public RotatoryKnobView(Context context) { 
    super(context); 
    initialize(); 
    } 

    public RotatoryKnobView(Context context, AttributeSet attrs) 
    { 
    super(context, attrs); 
    initialize(); 
    } 

    public RotatoryKnobView(Context context, AttributeSet attrs, int defStyle) 
    { 
    super(context, attrs, defStyle); 
    initialize(); 
    } 

    private float getTheta(float x, float y) 
    { 
    float sx = x - (getWidth()/2.0f); 
    float sy = y - (getHeight()/2.0f); 

    float length = (float)Math.sqrt(sx*sx + sy*sy); 
    float nx = sx/length; 
    float ny = sy/length; 
    float theta = (float)Math.atan2(ny, nx); 

    final float rad2deg = (float)(180.0/Math.PI); 
    float thetaDeg = theta*rad2deg; 

    return (thetaDeg < 0) ? thetaDeg + 360.0f : thetaDeg; 
    } 

    public void initialize() 
    { 
    this.setImageResource(R.drawable.rotoron); 
    setOnTouchListener(new OnTouchListener() 
     { 
@Override 
public boolean onTouch(View v, MotionEvent event) { 
    float x = event.getX(0); 
    float y = event.getY(0); 
    float theta = getTheta(x,y); 

    switch(event.getAction() & MotionEvent.ACTION_MASK) 
    { 
    case MotionEvent.ACTION_POINTER_DOWN: 
     theta_old = theta; 
     break; 
    case MotionEvent.ACTION_MOVE: 
     invalidate(); 
     float delta_theta = theta - theta_old; 
     theta_old = theta; 
     int direction = (delta_theta > 0) ? 1 : -1; 
     angle += 5*direction; 
     notifyListener(angle+20); 
     break; 
    } 
    return true; 
} 
     }); 
    } 

    private void notifyListener(float arg) 
    { 
    if (null!=listener) 
     listener.onKnobChanged(arg); 
    } 

    protected void onDraw(Canvas c) 
    {if(angle==257f){ 
     try { 
      synchronized (c) { 

       c.wait(5000); 
       angle=260f; 
      } 

     } catch (InterruptedException e) { 
     } 
    } 
    else if(angle==-16f) 
    { 
     try { 
      synchronized (c) { 
       c.wait(5000); 
       angle=-20f; 
      } 

     } catch (InterruptedException e) { 

     } 
    } 
    else 
     if(angle>260f) 
      { 

      angle=-20f; 
     } 
     else if(angle<-20f) 
      { 

      angle=260f; 
     } 
     else{ 
      c.rotate(angle,getWidth()/2,getHeight()/2); 

     } 
    super.onDraw(c); 
    } 
} 
+1

Si prega di smettere di cambiare la domanda a qualcosa di completamente diverso, al fine di invalidare le risposte qui sotto. –

risposta

5

Penso che la risposta definitiva è quello di implementare la propria classe estendendo SurfaceView e poi override onDraw (Tela)

È quindi possibile utilizzare le routine di tela per rendere il vostro controllo.

Ci sono molti buoni esempi là fuori su google.

Per iniziare inizializzare la superficie vista:

// So things actually render 
    setDrawingCacheEnabled(true); 
    setWillNotDraw(false); 
    setZOrderOnTop(true); 

    // Controls the drawing thread. 
    getHolder().addCallback(new CallbackSurfaceView()); 

Override OnDraw e aggiungere le routine di rendering. Puoi metterli a strati mentre vai.

public void onDraw(Canvas canvas) { 

     // Always Draw 
     super.onDraw(canvas); 

     drawBackground(canvas); 

     drawKnobIndentWell(canvas); 

     drawKnob(canvas); 

     drawKnobLED(canvas); //etc.... 
} 

Un esempio di una richiamata ed una filettatura aggiornamento:

/** 
* This is the drawing callback. 
* It handles the creation and destruction of the drawing thread when the 
* surface for drawing is created and destroyed. 
*/ 
class CallbackSurfaceView implements SurfaceHolder.Callback { 
    Thread threadIndeterminant; 
    RunnableProgressUpdater runnableUpdater; 
    boolean done = false; 

    /** 
    * Kills the running thread. 
    */ 
    public void done() { 
     done = true; 
     if (null != runnableUpdater) { 
      runnableUpdater.done(); 
     } 
    } 

    /** 
    * Causes the UI to render once. 
    */ 
    public void needRedraw() { 
     if (runnableUpdater != null) { 
      runnableUpdater.needRedraw(); 
     } 
    } 


    /** 
    * When the surface is created start the drawing thread. 
    * @param holder 
    */ 
    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
     if (!done) { 
      threadIndeterminant = new Thread(runnableUpdater = new RunnableProgressUpdater()); 
      threadIndeterminant.start(); 
     } 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 

    } 

    /** 
    * When the surface is destroyed stop the drawing thread. 
    * @param holder 
    */ 
    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 

     if (null != runnableUpdater) { 
      runnableUpdater.done(); 
      threadIndeterminant = null; 
      runnableUpdater = null; 
     } 
    } 
} 

/** 
* This is the runnable for the drawing operations. It is started and stopped by the callback class. 
*/ 
class RunnableProgressUpdater implements Runnable { 

    boolean surfaceExists = true; 
    boolean needRedraw = false; 

    public void done() { 
     surfaceExists = false; 
    } 

    public void needRedraw() { 
     needRedraw = true; 
    } 


    @Override 
    public void run() { 

     canvasDrawAndPost(); 

     while (surfaceExists) { 

      // Renders continuously during a download operation. 
      // Otherwise only renders when requested. 
      // Necessary so that progress bar and cirlce activity update. 
      if (syncContext.isRunning()) { 
       canvasDrawAndPost(); 
       needRedraw = true; 
      } else if (needRedraw) { 
       canvasDrawAndPost(); 
       needRedraw = false; 
      } 


      try { 
       Thread.sleep(100); 
      } catch (InterruptedException e) { 
       // Don't care 
      } 
     } 


     // One final update 
     canvasDrawAndPost(); 

    } 

    /** 
    * Routine the redraws the controls on each loop. 
    */ 
    private synchronized void canvasDrawAndPost() { 
     Canvas canvas = getHolder().lockCanvas(); 

     if (canvas != null) { 
      try { 
       draw(canvas); 
      } finally { 
       getHolder().unlockCanvasAndPost(canvas); 
      } 
     } 
    } 


} 

Se si decide di seguire questa strada è possibile personalizzare il vostro controllo da XML utilizzando valori personalizzati.

<com.killerknob.graphics.MultimeterVolumeControl 
     android:id="@+id/volume_control" 
     android:layout_below="@id/divider_one" 
     android:background="@android:color/white" 
     android:layout_width="match_parent" 
     android:layout_height="60dp" 
     android:minHeight="60dp" 
     custom:ledShadow="#357BBB" 
     custom:ledColor="#357BBB" 
     custom:knobBackground="@color/gray_level_13" 
     custom:knobColor="@android:color/black" 
     /> 

Quando si crea un controllo personalizzato, si fa riferimento al nome del pacchetto. È possibile creare una variabile personalizzata in un file di risorse sotto/valori e quindi fare riferimento a nella classe.

Maggiori dettagli qui:

http://developer.android.com/training/custom-views/create-view.html

Questo può essere più lavoro poi si vogliono fare, ma penso che si finirà con un controllo più professionale e le animazioni saranno più liscia.

In ogni caso, sembra un progetto divertente. In bocca al lupo.

+0

Aggiunto un collegamento che mostra come utilizzare valori personalizzati e fare riferimento a una classe di vista personalizzata. – mjstam

+0

Non è necessario il codice di aggiornamento progressione. Ho estratto quel codice da un progetto esistente per fornire un esempio di un thread di aggiornamento e il meccanismo di callback. – mjstam

+2

Non posso essere un codice commerciale e non mi appartiene. – mjstam

5

È possibile impostare un angolo fisso e utilizzare PostDelay per cancellarlo dopo 2 secondi.

public class RotatoryKnobView extends ImageView { 

    private float angle = -20f; 
    private float theta_old=0f; 

    private RotaryKnobListener listener; 

    private Float fixedAngle; 
    private float settleAngle; 

    private Runnable unsetFixedAngle = new Runnable() { 
     @Override 
     public void run() { 
      angle = settleAngle; 
      fixedAngle = null; 
      invalidate(); 
     } 
    }; 

    public interface RotaryKnobListener { 
     public void onKnobChanged(float arg); 
    } 

    public void setKnobListener(RotaryKnobListener l) 
    { 
     listener = l; 
    } 

    public RotatoryKnobView(Context context) { 
     super(context); 
     initialize(); 
    } 

    public RotatoryKnobView(Context context, AttributeSet attrs) 
    { 
     super(context, attrs); 
     initialize(); 
    } 

    public RotatoryKnobView(Context context, AttributeSet attrs, int defStyle) 
    { 
     super(context, attrs, defStyle); 
     initialize(); 
    } 

    private float getTheta(float x, float y) 
    { 
     float sx = x - (getWidth()/2.0f); 
     float sy = y - (getHeight()/2.0f); 

     float length = (float)Math.sqrt(sx*sx + sy*sy); 
     float nx = sx/length; 
     float ny = sy/length; 
     float theta = (float)Math.atan2(ny, nx); 

     final float rad2deg = (float)(180.0/Math.PI); 
     float thetaDeg = theta*rad2deg; 

     return (thetaDeg < 0) ? thetaDeg + 360.0f : thetaDeg; 
    } 

    public void initialize() 
    { 
     this.setImageResource(R.drawable.rotoron); 
     setOnTouchListener(new OnTouchListener() 
     { 
      @Override 
      public boolean onTouch(View v, MotionEvent event) { 
       float x = event.getX(0); 
       float y = event.getY(0); 
       float theta = getTheta(x,y); 

       switch(event.getAction() & MotionEvent.ACTION_MASK) 
       { 
        case MotionEvent.ACTION_POINTER_DOWN: 
         theta_old = theta; 
         break; 
        case MotionEvent.ACTION_MOVE: 
         invalidate(); 
         float delta_theta = theta - theta_old; 
         theta_old = theta; 
         int direction = (delta_theta > 0) ? 1 : -1; 
         angle += 5*direction; 
         notifyListener(angle+20); 
         break; 
       } 
       return true; 
      } 
     }); 
    } 

    private void notifyListener(float arg) 
    { 
     if (null!=listener) 
      listener.onKnobChanged(arg); 
    } 

    void setFixedAngle(float angle, float settleAngle) { 
     fixedAngle = angle; 
     this.settleAngle = settleAngle; 
     postDelayed(unsetFixedAngle, 2000); 
    } 

    protected void onDraw(Canvas c) 
    { 
     if(fixedAngle==null) { 
      if (angle > 270) { 
       setFixedAngle(270, -15); 
      } else if (angle < -20f) { 
       setFixedAngle(-20, 260); 
      } 
     } 
     Log.d("angle", "angle: " + angle + " fixed angle: " + fixedAngle); 
     c.rotate(fixedAngle == null ? angle : fixedAngle,getWidth()/2,getHeight()/2); 

     super.onDraw(c); 
    } 
} 

`

+2

Ho cambiato le chiamate setFixedAngle() nel codice di esempio. –

+2

Spiacente, non riesco a capire il comportamento desiderato della manopola. Potresti specificare più chiaramente? –

+2

Risposta molto bella –