2011-10-01 20 views
8

Creé una vista personalizada desde cero. Extendido View y anulado onDraw(). Cuando se reduce la animación de la vista, genero una animación personalizada utilizando compensaciones. por ej.¿Cómo puedo dibujar una vista animada en Android?

while(!isOnTop){ 
mOffset++; 

//draw the component a a it higher using the offset 

if(position == 0) 
isOnTop==true; 
invalidate(); 

} 

La idea es que mis marcos vienen de invalidarlo. El problema es que la invalidación de esta vista puede venir simplemente desplazando una vista de lista en la misma pantalla.

Esta "invalidación compartida()" causa un retraso en mi animación. ¿Hay alguna manera de salir de ese retraso?

¿Tiene alguna otra sugerencia de realizar animaciones en ese entorno compartido? Crear una animación usando un hilo separado que calcula el desplazamiento también necesita llamadas de invalidación forzadas() para mostrar la animación (corríjame si estoy equivocado).

¿La única solución para realizar la animación es, por ejemplo, 10 solicitudes de invalidación con un paso más grande? Se aliviará el retraso, pero creo que puedo usar un enfoque diferente sobre eso.

Respuesta

4

Dado que esta pregunta tiene cierto interés, responderé.

La mejor manera de hacerlo es tener un hilo de lienzo por separado. Un lienzo "separado" solo se puede lograr con un SurfaceView. LunarLanding es un excelente ejemplo de ese uso. Cada cuadro se calcula por separado de la vista principal, compartiendo solo el tiempo de CPU, no el tiempo de dibujo. Por lo tanto, es más rápido, incluso con la combinación de, por ejemplo, una vista normal en la parte superior y una vista animada en la parte inferior.

Pero debe establecer un intervalo si se encuentra en ese entorno compartido. Ese intervalo se usa para el límite de FPS. Si no configura el límite de FPS, la CPU se ejecutará de forma salvaje logrando obtener una buena animación en el SurfaceView si estuviera solo. Limitarlo a 60 fps o incluso menos hará el truco para dibujar todas las vistas de manera eficiente sin sobrecarga de la CPU.

Así que vea el hilo de dibujo del Lunar Landing de las demostraciones de la API y establezca un límite de FPS.

private long timeNow; 
    private long timeDelta; 
    private long timePrevFrame; 

    private void capFps(int fps) { 
      timeNow = System.currentTimeMillis(); 
      timeDelta = timeNow - timePrevFrame;   

      try { 

// ps siempre se puede fijar en lugar de 16 1000/60 fps fps para evitar el cálculo cada vez que

Thread.sleep((1000/fps) - timeDelta); 
      } catch (InterruptedException e) { 

      } 

      timePrevFrame = System.currentTimeMillis(); 
    } 

y luego el hilo de dibujo se verá algo como esto:

@Override 
    public void run() { 
     Canvas c; 

     while (run) { 
      c = null; 
      sleepFps(60, false); 
      try { 
       synchronized (surfaceHolder) { 
        c = surfaceHolder.lockCanvas(null); 
        widgetView.doDraw(c); 
       } 
      } finally { 
       if (c != null) { 
        surfaceHolder.unlockCanvasAndPost(c); 
       } 
      } 

     } 
    } 
+0

Lo sentimos, esto es * camino * más complicado que a menudo necesaria, y una SurfaceView tiene muchos compromisos que lo hacen a menudo no es la mejor solución. – hackbod

+0

Sí, pero es el mejor para tener múltiples vistas animadas juntas. la pregunta fue cuál es la "mejor" manera, aunque gracias por la respuesta – weakwire

+0

Esta es la forma en que estoy familiarizado con j2me. Si no te gustan los cálculos, siempre puedes omitirlo y dormir por tiempo constante. –

23

"Lo que es mejor", por supuesto, depende en gran medida de exactamente lo que está tratando de hacer. No has dicho lo que intentas lograr, así que solo podemos adivinar qué es lo mejor para ti.

Aquí hay algunas cosas simples:

Aquí es un simple invalidate repitió usando Handler:

long mAnimStartTime; 

Handler mHandler = new Handler(); 
Runnable mTick = new Runnable() { 
    public void run() { 
     invalidate(); 
     mHandler.postDelayed(this, 20); // 20ms == 60fps 
    } 
} 

void startAnimation() { 
    mAnimStartTime = SystemClock.uptimeMillis(); 
    mHandler.removeCallbacks(mTick); 
    mHandler.post(mTick); 
} 

void stopAnimation() { 
    mHandler.removeCallbacks(mTick); 
} 
+1

invalidate() no es instantáneo. Puede tomar más de 20 ms porque se necesitan muchas vistas para invalidar. La vista tiene que esperar hasta que todas hayan finalizado (al menos antes de 3.0). postDelayed introducirá más retraso. Limitar fps de esa manera no es bueno. Corregirme si estoy equivocado. – weakwire

+2

No realmente. Si invalidate() toma más de 20 ms, tiene serios problemas en la forma en que ha estructurado su jerarquía de vistas. La gran mayoría de las animaciones dentro de Windows en la plataforma estándar usan vistas regulares con invalidate() y pueden alcanzar 60fps. Solo necesita asegurarse de no hacer cosas en su jerarquía de vistas, como tener múltiples grandes mapas de bits opacos uno encima del otro o escalar eso haciendo que sea más lento ... pero no quiere hacer eso de todos modos. – hackbod

+12

¿No son 20 ms 50 fps? –

Cuestiones relacionadas