studio screensize rotate react how configchanges change android math layout view rotation

android - screensize - ¿Cómo detener el lienzo para que no gire durante 2 segundos en ángulos específicos?



onconfigurationchanged android (2)

Hice una perilla giratoria, pero quiero detener la perilla en ángulos específicos durante 2 segundos. Quiero detenerlo en 260f y -20f.

¿Alguien puede sugerir cómo hacerlo?

Este es el código de un blog. Hice muchos cambios de acuerdo con mis requisitos.

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


Creo que la respuesta final aquí es implementar tu propia clase extendiendo SurfaceView y luego anulando onDraw (Canvas canvas)

A continuación, puede usar las rutinas de Canvas para representar su control.

Hay muchos buenos ejemplos si google.

Para comenzar, inicialice la vista de superficie:

// So things actually render setDrawingCacheEnabled(true); setWillNotDraw(false); setZOrderOnTop(true); // Controls the drawing thread. getHolder().addCallback(new CallbackSurfaceView());

Anule onDraw y agregue sus rutinas de representación. Puede colocarlos sobre la marcha.

public void onDraw(Canvas canvas) { // Always Draw super.onDraw(canvas); drawBackground(canvas); drawKnobIndentWell(canvas); drawKnob(canvas); drawKnobLED( canvas ); //etc.... }

Un ejemplo de devolución de llamada y un hilo de actualización:

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

Si decide seguir esta ruta, puede personalizar su control desde XML utilizando valores personalizados.

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

Cuando crea un control personalizado lo referencia por su nombre de paquete. Usted crea una variable personalizada en un archivo de recursos en / values ​​y luego los referencia en su clase.

Más detalles aquí:

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

Esto puede ser más trabajo que desea hacer, pero creo que terminará con un control de aspecto más profesional y las animaciones serán más suaves.

En cualquier caso, parece un proyecto divertido. Buena suerte.


Puede establecer un ángulo fijo y usar postDelayed para borrarlo después de 2 segundos.

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

`