Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 package android.graphics.drawable;
 
 
 
An object used to create frame-by-frame animations, defined by a series of Drawable objects, which can be used as a View object's background.

The simplest way to create a frame-by-frame animation is to define the animation in an XML file, placed in the res/drawable/ folder, and set it as the background to a View object. Then, call start() to run the animation.

An AnimationDrawable defined in XML consists of a single <animation-list> element, and a series of nested <item> tags. Each item defines a frame of the animation. See the example below.

spin_animation.xml file in res/drawable/ folder:

<!-- Animation frames are wheel0.png -- wheel5.png files inside the
 res/drawable/ folder -->
 <animation-list android:id="selected" android:oneshot="false">
    <item android:drawable="@drawable/wheel0" android:duration="50" />
    <item android:drawable="@drawable/wheel1" android:duration="50" />
    <item android:drawable="@drawable/wheel2" android:duration="50" />
    <item android:drawable="@drawable/wheel3" android:duration="50" />
    <item android:drawable="@drawable/wheel4" android:duration="50" />
    <item android:drawable="@drawable/wheel5" android:duration="50" />
 </animation-list>

Here is the code to load and play this animation.

 // Load the ImageView that will host the animation and
 // set its background to our AnimationDrawable XML resource.
 ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image);
 img.setBackgroundResource(R.drawable.spin_animation);

 // Get the background, which has been compiled to an AnimationDrawable object.
 AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground();

 // Start the animation (looped playback by default).
 frameAnimation.start();
 

For more information, see the guide to Animation Resources.

Attr:
ref android.R.styleable#AnimationDrawable_visible
Attr:
ref android.R.styleable#AnimationDrawable_variablePadding
Attr:
ref android.R.styleable#AnimationDrawable_oneshot
Attr:
ref android.R.styleable#AnimationDrawableItem_duration
Attr:
ref android.R.styleable#AnimationDrawableItem_drawable
 
 public class AnimationDrawable extends DrawableContainer implements RunnableAnimatable {
     private final AnimationState mAnimationState;
     private int mCurFrame = -1;
     private boolean mMutated;
 
     public AnimationDrawable() {
         this(nullnull);
     }
 
     @Override
     public boolean setVisible(boolean visibleboolean restart) {
         boolean changed = super.setVisible(visiblerestart);
         if (visible) {
             if (changed || restart) {
                 setFrame(0, truetrue);
             }
         } else {
             unscheduleSelf(this);
         }
         return changed;
     }

    

Starts the animation, looping if necessary. This method has no effect if the animation is running.

    public void start() {
        if (!isRunning()) {
            run();
        }
    }

    

Stops the animation. This method has no effect if the animation is not running.

    public void stop() {
        if (isRunning()) {
            unscheduleSelf(this);
        }
    }

    

Indicates whether the animation is currently running or not.

Returns:
true if the animation is running, false otherwise
    public boolean isRunning() {
        return  > -1;
    }

    

This method exists for implementation purpose only and should not be called directly. Invoke start() instead.

See also:
start()
    public void run() {
        nextFrame(false);
    }
    @Override
    public void unscheduleSelf(Runnable what) {
         = -1;
        super.unscheduleSelf(what);
    }

    

Returns:
The number of frames in the animation
    public int getNumberOfFrames() {
        return .getChildCount();
    }
    
    

Returns:
The Drawable at the specified frame index
    public Drawable getFrame(int index) {
        return .getChildren()[index];
    }
    
    

Returns:
The duration in milliseconds of the frame at the specified index
    public int getDuration(int i) {
        return .[i];
    }
    
    

Returns:
True of the animation will play once, false otherwise
    public boolean isOneShot() {
        return .;
    }
    
    
Sets whether the animation should play once or repeat.

Parameters:
oneShot Pass true if the animation should only play once
    public void setOneShot(boolean oneShot) {
        . = oneShot;
    }
    
    
Add a frame to the animation

Parameters:
frame The frame to add
duration How long in milliseconds the frame should appear
    public void addFrame(Drawable frameint duration) {
        .addFrame(frameduration);
        if ( < 0) {
            setFrame(0, truefalse);
        }
    }
    
    private void nextFrame(boolean unschedule) {
        int next = +1;
        final int N = .getChildCount();
        if (next >= N) {
            next = 0;
        }
        setFrame(nextunschedule, !. || next < (N - 1));
    }
    private void setFrame(int frameboolean unscheduleboolean animate) {
        if (frame >= .getChildCount()) {
            return;
        }
         = frame;
        selectDrawable(frame);
        if (unschedule) {
            unscheduleSelf(this);
        }
        if (animate) {
            scheduleSelf(this, SystemClock.uptimeMillis() + .[frame]);
        }
    }
    @Override
    public void inflate(Resources rXmlPullParser parserAttributeSet attrs)
            throws XmlPullParserExceptionIOException {
        
        TypedArray a = r.obtainAttributes(attrs,
                .....);
        super.inflateWithAttributes(rparsera,
                .....);
        
                .....false));
            
        . = a.getBoolean(
                .....false);
        
        a.recycle();
        
        int type;
        final int innerDepth = parser.getDepth()+1;
        int depth;
        while ((type=parser.next()) != . &&
                ((depth = parser.getDepth()) >= innerDepth || type != .)) {
            if (type != .) {
                continue;
            }
            if (depth > innerDepth || !parser.getName().equals("item")) {
                continue;
            }
            
            a = r.obtainAttributes(attrs.....);
            int duration = a.getInt(
                    ....., -1);
            if (duration < 0) {
                throw new XmlPullParserException(
                        parser.getPositionDescription()
                        + ": <item> tag requires a 'duration' attribute");
            }
            int drawableRes = a.getResourceId(
                    ....., 0);
            
            a.recycle();
            
            Drawable dr;
            if (drawableRes != 0) {
                dr = r.getDrawable(drawableRes);
            } else {
                while ((type=parser.next()) == .) {
                    // Empty
                }
                if (type != .) {
                    throw new XmlPullParserException(parser.getPositionDescription() +
                            ": <item> tag requires a 'drawable' attribute or child tag" +
                            " defining a drawable");
                }
                dr = Drawable.createFromXmlInner(rparserattrs);
            }
            
            .addFrame(drduration);
            if (dr != null) {
                dr.setCallback(this);
            }
        }
        setFrame(0, truefalse);
    }
    @Override
    public Drawable mutate() {
        if (! && super.mutate() == this) {
             = true;
        }
        return this;
    }
    private final static class AnimationState extends DrawableContainerState {
        private int[] mDurations;
        private boolean mOneShot;
        AnimationState(AnimationState origAnimationDrawable owner,
                Resources res) {
            super(origownerres);
            if (orig != null) {
                 = orig.mDurations;
                 = orig.mOneShot;
            } else {
                 = new int[getChildren().length];
                 = true;
            }
        }
        @Override
        public Drawable newDrawable() {
            return new AnimationDrawable(thisnull);
        }
        @Override
        public Drawable newDrawable(Resources res) {
            return new AnimationDrawable(thisres);
        }
        public void addFrame(Drawable drint dur) {
            // Do not combine the following. The array index must be evaluated before 
            // the array is accessed because super.addChild(dr) has a side effect on mDurations.
            int pos = super.addChild(dr);
            [pos] = dur;
        }
        @Override
        public void growArray(int oldSizeint newSize) {
            super.growArray(oldSizenewSize);
            int[] newDurations = new int[newSize];
            System.arraycopy(, 0, newDurations, 0, oldSize);
             = newDurations;
        }
    }
    private AnimationDrawable(AnimationState stateResources res) {
        AnimationState as = new AnimationState(statethisres);
         = as;
        setConstantState(as);
        if (state != null) {
            setFrame(0, truefalse);
        }
    }
New to GrepCode? Check out our FAQ X