2011-01-10 9 views
7

Czy możliwe jest utworzenie losowania, które ma jakąś animację, niezależnie od tego, czy jest to animacja klatka po klatce, obrót itp., Która jest zdefiniowana jako rysowanie xml i może być reprezentowana przez pojedynczy obiekt Drawable bez konieczności radzenia sobie z animacja w kodzie?Czy można animować ciąg dalszy?

Jak sobie z tym poradzę: Mam listę i każda pozycja na tej liście może kiedyś mieć coś z tym związanego. Podczas gdy to się dzieje, chciałbym mieć animację postępu wirowania podobną do nieokreślonego ProgressBar. Ponieważ może być ich kilka na ekranie, pomyślałem, że jeśli wszyscy dzielą tę samą Szufladę, będą potrzebowali tylko jednej instancji w pamięci, a ich animacje będą zsynchronizowane, abyś nie miał pęczków obracających się obiektów w różnych punktach. w wirującej animacji.

Nie jestem związany z tym podejściem. Po prostu staram się wymyślić najbardziej efektywny sposób wyświetlania kilku obracających się animacji postępu i idealnie je zsynchronizować, aby były spójne pod względem wyglądu.

Dzięki

W odpowiedzi na odpowiedź Sybiam za:

Próbowałem wdrożenie RotateDrawable ale nie obraca się.

Oto mój xml dla rozciągliwej tej pory:

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

Próbowałem przy użyciu tego rozciągliwej jako src i tle ImageView i obie strony produkowane tylko non-obracający obraz.

Czy jest coś, co musi rozpocząć rotację obrazu?

+0

Zamówienie http://stackoverflow.com/a/30901885/1052261 –

Odpowiedz

1

Możesz rozpocząć od studiowania projektu ProgressBar2 z projektu API (jest on dostępny jako część SDK). Zwróć szczególną uwagę na R.layout.progressbar_2.

7

Drawables

Nie pójdziesz! I ten dla RotateDrawable. Wierzę, że od Doktora powinno być dość ciasno. Możesz zdefiniować wszystko w pliku xml i ustawić tło widoku jako szuflady xml. /drawable/myrotate.xml -> @ drawable/myrotate

Edytuj: Oto odpowiedź, którą znalazłem tutaj. Drawable Rotating around its center Android

Edycja 2: Masz rację, że RotateDrawable wygląda na zepsuty. Nie wiem, że też tego spróbowałem. Nie udało mi się jeszcze tego dokonać. Ale udało mi się go obrócić. Musisz użyć setLevel, który go obróci. Choć nie wygląda to naprawdę użytecznie. Przeglądałem kod, a RotateDrawable nawet nie nadmuchuje czasu trwania animacji, a obecny obrót wydaje się dziwnie wykorzystywać poziom jako miarę rotacji. Wierzę, że musisz użyć go z AnimationDrawable, ale tutaj znowu. Po prostu rozbił się dla mnie. Nie korzystałem jeszcze z tej funkcji, ale planowałem ją wykorzystać w przyszłości. Przeglądałem sieć, a RotateDrawable wydaje się być bardzo nieudokumentowana jak prawie każdy obiekt Drawable.

+0

Próbowałem moje szczęście z RotateDrawable i nie animował. Więcej szczegółów w moim oryginalnym pytaniu. Jakieś pojęcie o tym, co robię źle? – cottonBallPaws

+0

Czy uruchomiłeś animację? –

+1

Więc RotateDrawable musi być programowo rozpoczęty? Sądzę, że tego rodzaju porażki mają na celu próbowanie uporania się z tym w xml. Jak byś to zaczął? – cottonBallPaws

15

Tak! Klucz (nieudokumentowany), który odkryłem po przeczytaniu kodu ProgressBar, polega na tym, że musisz zadzwonić pod numer Drawable.setLevel() w onDraw(), aby uzyskać efekt <rotate>.ProgressBar działa coś takiego (dodatkowy kod nieważnym pominięta):

odkształcalne XML:

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

W 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 jest stałą, a zawsze jest 10.000 (zgodnie z docs). ANIM_PERIOD to okres Twojej animacji w milisekundach.

Niestety ponieważ trzeba zmodyfikować onDraw() nie można po prostu umieścić ten rozciągliwej w sposób ImageView od ImageView nigdy się nie zmienia poziomu rozciągliwej. Możesz jednak zmienić poziom kreślenia z poza z ImageView. ProgressBar (ab) używa AlphaAnimation do ustawienia poziomu. Więc możesz zrobić coś takiego:

mMyImageView.setImageDrawable(myDrawable); 

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

Może działać, ale nie testowałem go.

Edit

Tam jest rzeczywiście metoda ImageView.setImageLevel() więc może być tak proste, jak:

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

Czy nie ma rozwiązania, które jest tylko w XML? –

+0

'drawable.setLevel()' jest wygodniejsze. np .: ObjectAnimator.ofInt (drawable, "level", 0, 10000) ' – ipcjs

+0

To jest ... w mojej odpowiedzi. – Timmmm

2

Oto jeden z możliwych sposobów (szczególnie przydatne, gdy masz rozciągliwej gdzieś ustawić i trzeba animowanie to). Chodzi o to, aby owinąć szufladę i ozdobić ją animacją. W moim przypadku, miałem go obrócić, tak poniżej można znaleźć przykładową realizację:

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

i można go używać tak (nawigacji ikonę na pasku narzędzi obraca się o 360 stopni):

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

To powinnam „t trudne dodanie metodę z obrócić go nieokreślony (setRepeatMode INFINITE for animator)

+0

Co to jest @AnimatorSetter, z którym się nie kompiluje. –

+0

instanceof VectorDrawable powoduje awarię na pre-Lollipop i nie jest wymagana, chyba że jest to wektor. –

+0

Również ta klasa będzie musiała być przechowywana w ProGuard. –

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

poziom jest interpulting o wartości od 0 do 100000. rzeczywiste wartości animacji są metodami ustawiających

0

można użyć stateListAnimator

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

i odbić

<?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>