2015-11-17 37 views
22

我做了一個旋鈕,但我想停止旋鈕在特定的角度2秒。我想在260f和-20f停止它。如何暫停畫布在特定角度旋轉2秒?

任何人都可以建議如何做到這一點?

這是來自博客的代碼。根據我的要求我做了很多改變。

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

請停止改變問題的東西,以無效下面的答案完全不同。 –

回答

5

我覺得這裏最終的答案是通過延長SurfaceView,然後重寫onDraw(帆布油畫)來實現自己的類

然後,您可以使用Canvas例程來呈現你的控制。

如果你是谷歌,那裏有很多很好的例子。

要開始初始化面視圖:

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

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

覆蓋的onDraw並添加你的渲染程序。您可以隨時將它們分層排列 。

public void onDraw(Canvas canvas) { 

     // Always Draw 
     super.onDraw(canvas); 

     drawBackground(canvas); 

     drawKnobIndentWell(canvas); 

     drawKnob(canvas); 

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

一個回調的例子和更新線程:

/** 
* 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); 
      } 
     } 
    } 


} 

如果你決定走這條路線,你可以自定義使用 自定義值XML的控制。

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

當您創建一個自定義控件時,通過它的包名引用它。 您可以在/ values下的資源文件中創建自定義變量,然後在您的課程中引用 。

更多細節在這裏:

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

這可能是更多的工作,那麼你想做的事,但我認爲你會落得一個更專業的控制和動畫更加順暢。

無論如何,看起來像一個有趣的項目。祝你好運。

+0

添加了一個鏈接,顯示如何使用自定義值並引用自定義視圖類。 – mjstam

+0

您不需要進度更新代碼。我從現有項目中提取代碼以提供更新線程和回調機制的示例。 – mjstam

+2

我不能它是商業代碼,不屬於我。 – mjstam

5

您可以設置一個固定角度並使用postDelayed在2秒後清除它。

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

我在示例代碼中更改了setFixedAngle()調用。 –

+2

對不起,我無法理解旋鈕的期望行爲。你能指出更清楚嗎? –

+2

非常好的答案 –