AnimatedStateListDrawablepublic class AnimatedStateListDrawable extends StateListDrawable Drawable containing a set of Drawable keyframes where the currently displayed
keyframe is chosen based on the current state set. Animations between
keyframes may optionally be defined using transition elements.
This drawable can be defined in an XML file with the
<animated-selector> element. Each keyframe Drawable is defined in a
nested <item> element. Transitions are defined in a nested
<transition> element. |
Fields Summary |
---|
private static final String | LOGTAG | private static final String | ELEMENT_TRANSITION | private static final String | ELEMENT_ITEM | private AnimatedStateListState | mState | private Transition | mTransitionThe currently running transition, if any. | private int | mTransitionToIndexIndex to be set after the transition ends. | private int | mTransitionFromIndexIndex away from which we are transitioning. | private boolean | mMutated |
Constructors Summary |
---|
public AnimatedStateListDrawable()
this(null, null);
| private AnimatedStateListDrawable(AnimatedStateListState state, android.content.res.Resources res)
super(null);
// Every animated state list drawable has its own constant state.
final AnimatedStateListState newState = new AnimatedStateListState(state, this, res);
setConstantState(newState);
onStateChange(getState());
jumpToCurrentState();
|
Methods Summary |
---|
public void | addState(int[] stateSet, Drawable drawable, int id)Add a new drawable to the set of keyframes.
if (drawable == null) {
throw new IllegalArgumentException("Drawable must not be null");
}
mState.addStateSet(stateSet, drawable, id);
onStateChange(getState());
| public void | addTransition(int fromId, int toId, T transition, boolean reversible)Adds a new transition between keyframes.
if (transition == null) {
throw new IllegalArgumentException("Transition drawable must not be null");
}
mState.addTransition(fromId, toId, transition, reversible);
| public void | applyTheme(android.content.res.Resources.Theme theme)
super.applyTheme(theme);
final AnimatedStateListState state = mState;
if (state == null || state.mAnimThemeAttrs == null) {
return;
}
final TypedArray a = theme.resolveAttributes(
state.mAnimThemeAttrs, R.styleable.AnimatedRotateDrawable);
updateStateFromTypedArray(a);
a.recycle();
init();
| public void | clearMutated()
super.clearMutated();
mMutated = false;
| android.graphics.drawable.AnimatedStateListDrawable$AnimatedStateListState | cloneConstantState()
return new AnimatedStateListState(mState, this, null);
| public void | inflate(android.content.res.Resources r, org.xmlpull.v1.XmlPullParser parser, android.util.AttributeSet attrs, android.content.res.Resources.Theme theme)
final TypedArray a = obtainAttributes(
r, theme, attrs, R.styleable.AnimatedStateListDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedStateListDrawable_visible);
updateStateFromTypedArray(a);
a.recycle();
inflateChildElements(r, parser, attrs, theme);
init();
| private void | inflateChildElements(android.content.res.Resources r, org.xmlpull.v1.XmlPullParser parser, android.util.AttributeSet attrs, android.content.res.Resources.Theme theme)
int type;
final int innerDepth = parser.getDepth() + 1;
int depth;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& ((depth = parser.getDepth()) >= innerDepth
|| type != XmlPullParser.END_TAG)) {
if (type != XmlPullParser.START_TAG) {
continue;
}
if (depth > innerDepth) {
continue;
}
if (parser.getName().equals(ELEMENT_ITEM)) {
parseItem(r, parser, attrs, theme);
} else if (parser.getName().equals(ELEMENT_TRANSITION)) {
parseTransition(r, parser, attrs, theme);
}
}
| private void | init()
onStateChange(getState());
| public boolean | isStateful()
return true;
| public void | jumpToCurrentState()
super.jumpToCurrentState();
if (mTransition != null) {
mTransition.stop();
mTransition = null;
selectDrawable(mTransitionToIndex);
mTransitionToIndex = -1;
mTransitionFromIndex = -1;
}
| public Drawable | mutate()
if (!mMutated && super.mutate() == this) {
mState.mutate();
mMutated = true;
}
return this;
| protected boolean | onStateChange(int[] stateSet)
// If we're not already at the target index, either attempt to find a
// valid transition to it or jump directly there.
final int targetIndex = mState.indexOfKeyframe(stateSet);
boolean changed = targetIndex != getCurrentIndex()
&& (selectTransition(targetIndex) || selectDrawable(targetIndex));
// We need to propagate the state change to the current drawable, but
// we can't call StateListDrawable.onStateChange() without changing the
// current drawable.
final Drawable current = getCurrent();
if (current != null) {
changed |= current.setState(stateSet);
}
return changed;
| private int | parseItem(android.content.res.Resources r, org.xmlpull.v1.XmlPullParser parser, android.util.AttributeSet attrs, android.content.res.Resources.Theme theme)
// This allows state list drawable item elements to be themed at
// inflation time but does NOT make them work for Zygote preload.
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.AnimatedStateListDrawableItem);
final int keyframeId = a.getResourceId(R.styleable.AnimatedStateListDrawableItem_id, 0);
Drawable dr = a.getDrawable(R.styleable.AnimatedStateListDrawableItem_drawable);
a.recycle();
final int[] states = extractStateSet(attrs);
// Loading child elements modifies the state of the AttributeSet's
// underlying parser, so it needs to happen after obtaining
// attributes and extracting states.
if (dr == null) {
int type;
while ((type = parser.next()) == XmlPullParser.TEXT) {
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException(
parser.getPositionDescription()
+ ": <item> tag requires a 'drawable' attribute or "
+ "child tag defining a drawable");
}
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
return mState.addStateSet(states, dr, keyframeId);
| private int | parseTransition(android.content.res.Resources r, org.xmlpull.v1.XmlPullParser parser, android.util.AttributeSet attrs, android.content.res.Resources.Theme theme)
// This allows state list drawable item elements to be themed at
// inflation time but does NOT make them work for Zygote preload.
final TypedArray a = obtainAttributes(r, theme, attrs,
R.styleable.AnimatedStateListDrawableTransition);
final int fromId = a.getResourceId(
R.styleable.AnimatedStateListDrawableTransition_fromId, 0);
final int toId = a.getResourceId(
R.styleable.AnimatedStateListDrawableTransition_toId, 0);
final boolean reversible = a.getBoolean(
R.styleable.AnimatedStateListDrawableTransition_reversible, false);
Drawable dr = a.getDrawable(
R.styleable.AnimatedStateListDrawableTransition_drawable);
a.recycle();
// Loading child elements modifies the state of the AttributeSet's
// underlying parser, so it needs to happen after obtaining
// attributes and extracting states.
if (dr == null) {
int type;
while ((type = parser.next()) == XmlPullParser.TEXT) {
}
if (type != XmlPullParser.START_TAG) {
throw new XmlPullParserException(
parser.getPositionDescription()
+ ": <transition> tag requires a 'drawable' attribute or "
+ "child tag defining a drawable");
}
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
return mState.addTransition(fromId, toId, dr, reversible);
| private boolean | selectTransition(int toIndex)
final int fromIndex;
final Transition currentTransition = mTransition;
if (currentTransition != null) {
if (toIndex == mTransitionToIndex) {
// Already animating to that keyframe.
return true;
} else if (toIndex == mTransitionFromIndex && currentTransition.canReverse()) {
// Reverse the current animation.
currentTransition.reverse();
mTransitionToIndex = mTransitionFromIndex;
mTransitionFromIndex = toIndex;
return true;
}
// Start the next transition from the end of the current one.
fromIndex = mTransitionToIndex;
// Changing animation, end the current animation.
currentTransition.stop();
} else {
fromIndex = getCurrentIndex();
}
// Reset state.
mTransition = null;
mTransitionFromIndex = -1;
mTransitionToIndex = -1;
final AnimatedStateListState state = mState;
final int fromId = state.getKeyframeIdAt(fromIndex);
final int toId = state.getKeyframeIdAt(toIndex);
if (toId == 0 || fromId == 0) {
// Missing a keyframe ID.
return false;
}
final int transitionIndex = state.indexOfTransition(fromId, toId);
if (transitionIndex < 0) {
// Couldn't select a transition.
return false;
}
boolean hasReversibleFlag = state.transitionHasReversibleFlag(fromId, toId);
// This may fail if we're already on the transition, but that's okay!
selectDrawable(transitionIndex);
final Transition transition;
final Drawable d = getCurrent();
if (d instanceof AnimationDrawable) {
final boolean reversed = state.isTransitionReversed(fromId, toId);
transition = new AnimationDrawableTransition((AnimationDrawable) d,
reversed, hasReversibleFlag);
} else if (d instanceof AnimatedVectorDrawable) {
final boolean reversed = state.isTransitionReversed(fromId, toId);
transition = new AnimatedVectorDrawableTransition((AnimatedVectorDrawable) d,
reversed, hasReversibleFlag);
} else if (d instanceof Animatable) {
transition = new AnimatableTransition((Animatable) d);
} else {
// We don't know how to animate this transition.
return false;
}
transition.start();
mTransition = transition;
mTransitionFromIndex = fromIndex;
mTransitionToIndex = toIndex;
return true;
| protected void | setConstantState(DrawableContainerState state)
super.setConstantState(state);
if (state instanceof AnimatedStateListState) {
mState = (AnimatedStateListState) state;
}
| public boolean | setVisible(boolean visible, boolean restart)
final boolean changed = super.setVisible(visible, restart);
if (mTransition != null && (changed || restart)) {
if (visible) {
mTransition.start();
} else {
// Ensure we're showing the correct state when visible.
jumpToCurrentState();
}
}
return changed;
| private void | updateStateFromTypedArray(android.content.res.TypedArray a)
final AnimatedStateListState state = mState;
// Account for any configuration changes.
state.mChangingConfigurations |= a.getChangingConfigurations();
// Extract the theme attributes, if any.
state.mAnimThemeAttrs = a.extractThemeAttrs();
state.setVariablePadding(a.getBoolean(
R.styleable.AnimatedStateListDrawable_variablePadding, state.mVariablePadding));
state.setConstantSize(a.getBoolean(
R.styleable.AnimatedStateListDrawable_constantSize, state.mConstantSize));
state.setEnterFadeDuration(a.getInt(
R.styleable.AnimatedStateListDrawable_enterFadeDuration, state.mEnterFadeDuration));
state.setExitFadeDuration(a.getInt(
R.styleable.AnimatedStateListDrawable_exitFadeDuration, state.mExitFadeDuration));
setDither(a.getBoolean(
R.styleable.AnimatedStateListDrawable_dither, state.mDither));
setAutoMirrored(a.getBoolean(
R.styleable.AnimatedStateListDrawable_autoMirrored, state.mAutoMirrored));
|
|