2011-01-10 16 views
7

¿Es posible crear un dibujante que tenga algún tipo de animación, ya sea una animación cuadro por cuadro, rotación, etc., que se defina como xml dibujable y se pueda representar mediante un único objeto Drawable sin tener que lidiar con la animación en el código?¿Es posible tener un dibujo animado dibujable?

Como estoy pensando en usarlo: Tengo una lista y cada elemento de esta lista puede que en algún momento le suceda algo. Mientras está sucediendo, me gustaría tener una animación de progreso girando similar a una ProgressBar indeterminada. Dado que también puede haber varios de estos en la pantalla, pensé que si todos compartían el mismo Drawable, solo necesitarían una instancia de él en la memoria y sus animaciones se sincronizarían para que no tuvieran un montón de objetos girando en varios puntos. en la animación de spinning.

No estoy apegado a este enfoque. Solo estoy tratando de pensar en la forma más eficiente de mostrar varias animaciones progresivas e idealmente sincronizarlas para que sean consistentes en apariencia.

Gracias

En respuesta a la respuesta de Sybiam:

que han intentado implementar un RotateDrawable pero no está girando.

Aquí es mi XML para el dibujable hasta ahora:

<?xml version="1.0" encoding="utf-8"?> 
<rotate xmlns:android="http://schemas.android.com/apk/res/android" 
android:drawable="@drawable/my_drawable_to_rotate" 
android:fromDegrees="0" 
android:toDegrees="360" 
android:pivotX="50%" 
android:pivotY="50%" 
android:duration="800" 
android:visible="true" /> 

He intentado usar que estirable como el src y fondo de un ImageView y en ambos sentidos producido sólo una imagen no giratoria.

¿Hay algo que deba iniciar la rotación de la imagen?

+0

Pedido http://stackoverflow.com/a/30901885/1052261 –

Respuesta

1

Puede comenzar estudiando el ProgressBar2 del proyecto Demos de la API (está disponible como parte del SDK). Específicamente, preste atención al R.layout.progressbar_2.

7

Drawables

hay que ir! Y este para RotateDrawable. Creo que desde el Doc debería ser bastante sencillo. Puede definir todo en un archivo xml y establecer el fondo de una vista como el xml dibujable. /drawable/myrotate.xml -> @ drawable/myrotate

Editar: Esta es una respuesta que encontré aquí. Drawable Rotating around its center Android

Editar 2: Tienes razón, el RotateDrawable parece estar roto. No sé, lo intenté también. Todavía no he tenido éxito en hacerlo animado. Pero sí logré rotarlo. Tienes que usar setLevel que lo rotará. Aunque no parece realmente útil. Busqué el código y el RotateDrawable ni siquiera inflar la duración de la animación y la rotación actual parece utilizar el nivel extrañamente como una medida para la rotación. Creo que debes usarlo con un AnimationDrawable pero aquí de nuevo. Simplemente se estrelló para mí. Todavía no he usado esa función pero planeé usarla en el futuro. Navegué por la web y el RotateDrawable parece estar muy indocumentado, como casi todos los objetos Drawable.

+0

probé suerte con el RotateDrawable y no animó. Más detalles en mi pregunta original. ¿Alguna idea de lo que estoy haciendo mal? – cottonBallPaws

+0

¿Comenzó la animación? –

+1

¿Entonces el RotateDrawable tiene que iniciarse programáticamente? Supongo que ese tipo de derrotas tiene el propósito de tratar de tratarlo en xml. ¿Cómo lo comenzarías? – cottonBallPaws

15

Sí! La clave (no documentada), que descubrí al leer el código ProgressBar es que debe llamar al Drawable.setLevel() en onDraw() para que el efecto <rotate> tenga algún efecto.El ProgressBar funciona algo como esto (código de importancia adicional omitido):

El XML dibujable:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android"> 
    <item> 
     <rotate 
      android:drawable="@drawable/spinner_48_outer_holo" 
      android:pivotX="50%" 
      android:pivotY="50%" 
      android:fromDegrees="0" 
      android:toDegrees="1080" /> 
    </item> 
    <item> 
     <rotate 
      android:drawable="@drawable/spinner_48_inner_holo" 
      android:pivotX="50%" 
      android:pivotY="50%" 
      android:fromDegrees="720" 
      android:toDegrees="0" /> 
    </item> 
</layer-list> 

En onDraw():

Drawable d = getDrawable(); 
    if (d != null) 
    { 
     // Translate canvas so a indeterminate circular progress bar with 
     // padding rotates properly in its animation 
     canvas.save(); 
     canvas.translate(getPaddingLeft(), getPaddingTop()); 

     long time = getDrawingTime(); 

     // I'm not sure about the +1. 
     float prog = (float)(time % ANIM_PERIOD+1)/(float)ANIM_PERIOD; 
     int level = (int)(MAX_LEVEL * prog); 
     d.setLevel(level); 
     d.draw(canvas); 

     canvas.restore(); 

     ViewCompat.postInvalidateOnAnimation(this); 
    } 

MAX_LEVEL es una constante, y siempre es 10.000 (según los documentos). ANIM_PERIOD es el período de su animación en milisegundos.

Por desgracia ya que se necesita para modificar onDraw() no se puede simplemente poner esto en un dibujable ImageView desde ImageView nunca cambia el nivel estirable. Sin embargo, es posible que pueda cambiar el nivel dibujable desde fuera deImageView. ProgressBar (ab) usa un AlphaAnimation para establecer el nivel. Por lo que haría algo como esto:

mMyImageView.setImageDrawable(myDrawable); 

ObjectAnimator anim = ObjectAnimator.ofInt(myDrawable, "level", 0, MAX_LEVEL); 
anim.setRepeatCount(ObjectAnimator.INFINITE); 
anim.start(); 

Podría funcionar, pero no he probado.

Editar

En realidad, hay un método ImageView.setImageLevel() por lo que podría ser tan simple como:

ObjectAnimator anim = ObjectAnimator.ofInt(myImageVew, "ImageLevel", 0, MAX_LEVEL); 
anim.setRepeatCount(ObjectAnimator.INFINITE); 
anim.start(); 
+0

¿No hay una solución que solo esté en XML? –

+0

'drawable.setLevel()' es más conveniente. por ejemplo: 'ObjectAnimator.ofInt (dibujable," nivel ", 0, 10000)' – ipcjs

+0

Eso es ... en mi respuesta. – Timmmm

2

Aquí está una de las posibles formas (especialmente útil cuando se tiene un Disponibles establece en alguna parte y la necesidad de animar eso). La idea es envolver el dibujo y decorarlo con animación. En mi caso, tuve que girar, por lo que a continuación se pueden encontrar implementación de ejemplo:

public class RotatableDrawable extends DrawableWrapper { 

    private float rotation; 
    private Rect bounds; 
    private ObjectAnimator animator; 
    private long defaultAnimationDuration; 

    public RotatableDrawable(Resources resources, Drawable drawable) { 
     super(vectorToBitmapDrawableIfNeeded(resources, drawable)); 
     bounds = new Rect(); 
     defaultAnimationDuration = resources.getInteger(android.R.integer.config_mediumAnimTime); 
    } 

    @Override 
    public void draw(Canvas canvas) { 
     copyBounds(bounds); 
     canvas.save(); 
     canvas.rotate(rotation, bounds.centerX(), bounds.centerY()); 
     super.draw(canvas); 
     canvas.restore(); 
    } 

    public void rotate(float degrees) { 
     rotate(degrees, defaultAnimationDuration); 
    } 

    public void rotate(float degrees, long millis) { 
     if (null != animator && animator.isStarted()) { 
      animator.end(); 
     } else if (null == animator) { 
      animator = ObjectAnimator.ofFloat(this, "rotation", 0, 0); 
      animator.setInterpolator(new AccelerateDecelerateInterpolator()); 
     } 
     animator.setFloatValues(rotation, degrees); 
     animator.setDuration(millis).start(); 
    } 

    @AnimatorSetter 
    public void setRotation(float degrees) { 
     this.rotation = degrees % 360; 
     invalidateSelf(); 
    } 

    /** 
    * Workaround for issues related to vector drawables rotation and scaling: 
    * https://code.google.com/p/android/issues/detail?id=192413 
    * https://code.google.com/p/android/issues/detail?id=208453 
    */ 
    private static Drawable vectorToBitmapDrawableIfNeeded(Resources resources, Drawable drawable) { 
     if (drawable instanceof VectorDrawable) { 
      Bitmap b = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); 
      Canvas c = new Canvas(b); 
      drawable.setBounds(0, 0, c.getWidth(), c.getHeight()); 
      drawable.draw(c); 
      drawable = new BitmapDrawable(resources, b); 
     } 
     return drawable; 
    } 
} 

y se puede utilizar de esta manera (icono de navegación barra de herramientas de rotación de 360 ​​grados):

backIcon = new RotatableDrawable(getResources(), toolbar.getNavigationIcon().mutate()); 
toolbar.setNavigationIcon(backIcon); 
backIcon.rotate(360); 

Se shouldn 't ser difícil añadir un método que va a girar nivel que indefinida (setRepeatMode INFINITE for animator)

+0

¿Qué es @AnimatorSetter? No compila con él. –

+0

instancia de VectorDrawable causa bloqueo en pre-Lollipop y no es necesario a menos que sea vector. –

+0

También esta clase deberá mantenerse en ProGuard. –

0
private ValueAnimator rotateDrawable(RotateDrawable drawable, int fromDegree, int toDegree) { 
    drawable.setFromDegrees(fromDegree); 
    drawable.setToDegrees(toDegree); 
    return ObjectAnimator.ofInt(drawable, "level", 0, 10000); 
} 

es el valor interpulting de 0 a 100000. los valores de animación reales son fijados por los métodos setter

0

puede utilizar stateListAnimator

<ImageView 
     android:id="@+id/your_id" 
     android:layout_width="200dp" 
     android:layout_height="200dp" 
     android:src="@drawable/your_drawable" 
     android:stateListAnimator="@anim/bounce" /> 

y rebote

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android" 

    android:interpolator="@android:anim/bounce"> 
    <translate 
     android:duration="900" 

     android:fromXDelta="100%p" 
     android:toXDelta="0%p" /> 
</set> 
Cuestiones relacionadas