am 91c091cf: Merge "State based animators for Views"
* commit '91c091cf7b732796d26971de6a508966e24d40a0': State based animators for Views
This commit is contained in:
@@ -1061,6 +1061,7 @@ package android {
|
||||
field public static final int startDelay = 16843746; // 0x10103e2
|
||||
field public static final int startOffset = 16843198; // 0x10101be
|
||||
field public static final deprecated int startYear = 16843132; // 0x101017c
|
||||
field public static final int stateListAnimator = 16843860; // 0x1010454
|
||||
field public static final int stateNotNeeded = 16842774; // 0x1010016
|
||||
field public static final int state_above_anchor = 16842922; // 0x10100aa
|
||||
field public static final int state_accelerated = 16843547; // 0x101031b
|
||||
@@ -2788,6 +2789,7 @@ package android.animation {
|
||||
public class AnimatorInflater {
|
||||
ctor public AnimatorInflater();
|
||||
method public static android.animation.Animator loadAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
|
||||
method public static android.animation.StateListAnimator loadStateListAnimator(android.content.Context, int) throws android.content.res.Resources.NotFoundException;
|
||||
}
|
||||
|
||||
public abstract class AnimatorListenerAdapter implements android.animation.Animator.AnimatorListener android.animation.Animator.AnimatorPauseListener {
|
||||
@@ -2984,6 +2986,12 @@ package android.animation {
|
||||
method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect);
|
||||
}
|
||||
|
||||
public class StateListAnimator {
|
||||
ctor public StateListAnimator();
|
||||
method public void addState(int[], android.animation.Animator);
|
||||
method public void jumpToCurrentState();
|
||||
}
|
||||
|
||||
public class TimeAnimator extends android.animation.ValueAnimator {
|
||||
ctor public TimeAnimator();
|
||||
method public void setTimeListener(android.animation.TimeAnimator.TimeListener);
|
||||
@@ -30834,6 +30842,7 @@ package android.view {
|
||||
method public final int getScrollY();
|
||||
method public java.lang.String getSharedElementName();
|
||||
method public int getSolidColor();
|
||||
method public android.animation.StateListAnimator getStateListAnimator();
|
||||
method protected int getSuggestedMinimumHeight();
|
||||
method protected int getSuggestedMinimumWidth();
|
||||
method public int getSystemUiVisibility();
|
||||
@@ -31098,6 +31107,7 @@ package android.view {
|
||||
method public void setSelected(boolean);
|
||||
method public void setSharedElementName(java.lang.String);
|
||||
method public void setSoundEffectsEnabled(boolean);
|
||||
method public void setStateListAnimator(android.animation.StateListAnimator);
|
||||
method public void setSystemUiVisibility(int);
|
||||
method public void setTag(java.lang.Object);
|
||||
method public void setTag(int, java.lang.Object);
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.content.res.Resources.NotFoundException;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.StateSet;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.animation.AnimationUtils;
|
||||
@@ -87,9 +88,86 @@ public class AnimatorInflater {
|
||||
}
|
||||
}
|
||||
|
||||
public static StateListAnimator loadStateListAnimator(Context context, int id)
|
||||
throws NotFoundException {
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = context.getResources().getAnimation(id);
|
||||
return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser));
|
||||
} catch (XmlPullParserException ex) {
|
||||
Resources.NotFoundException rnf =
|
||||
new Resources.NotFoundException(
|
||||
"Can't load state list animator resource ID #0x" +
|
||||
Integer.toHexString(id)
|
||||
);
|
||||
rnf.initCause(ex);
|
||||
throw rnf;
|
||||
} catch (IOException ex) {
|
||||
Resources.NotFoundException rnf =
|
||||
new Resources.NotFoundException(
|
||||
"Can't load state list animator resource ID #0x" +
|
||||
Integer.toHexString(id)
|
||||
);
|
||||
rnf.initCause(ex);
|
||||
throw rnf;
|
||||
} finally {
|
||||
if (parser != null) {
|
||||
parser.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static StateListAnimator createStateListAnimatorFromXml(Context context,
|
||||
XmlPullParser parser, AttributeSet attributeSet)
|
||||
throws IOException, XmlPullParserException {
|
||||
int type;
|
||||
StateListAnimator stateListAnimator = new StateListAnimator();
|
||||
|
||||
while (true) {
|
||||
type = parser.next();
|
||||
switch (type) {
|
||||
case XmlPullParser.END_DOCUMENT:
|
||||
case XmlPullParser.END_TAG:
|
||||
return stateListAnimator;
|
||||
|
||||
case XmlPullParser.START_TAG:
|
||||
// parse item
|
||||
Animator animator = null;
|
||||
if ("item".equals(parser.getName())) {
|
||||
int attributeCount = parser.getAttributeCount();
|
||||
int[] states = new int[attributeCount];
|
||||
int stateIndex = 0;
|
||||
for (int i = 0; i < attributeCount; i++) {
|
||||
int attrName = attributeSet.getAttributeNameResource(i);
|
||||
if (attrName == com.android.internal.R.attr.animation) {
|
||||
animator = loadAnimator(context,
|
||||
attributeSet.getAttributeResourceValue(i, 0));
|
||||
} else {
|
||||
states[stateIndex++] =
|
||||
attributeSet.getAttributeBooleanValue(i, false) ?
|
||||
attrName : -attrName;
|
||||
}
|
||||
|
||||
}
|
||||
if (animator == null) {
|
||||
animator = createAnimatorFromXml(context, parser);
|
||||
}
|
||||
|
||||
if (animator == null) {
|
||||
throw new Resources.NotFoundException(
|
||||
"animation state item must have a valid animation");
|
||||
}
|
||||
stateListAnimator
|
||||
.addState(StateSet.trimStateSet(states, stateIndex), animator);
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Animator createAnimatorFromXml(Context c, XmlPullParser parser)
|
||||
throws XmlPullParserException, IOException {
|
||||
|
||||
return createAnimatorFromXml(c, parser, Xml.asAttributeSet(parser), null, 0);
|
||||
}
|
||||
|
||||
|
||||
209
core/java/android/animation/StateListAnimator.java
Normal file
209
core/java/android/animation/StateListAnimator.java
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.animation;
|
||||
|
||||
import android.util.StateSet;
|
||||
import android.view.View;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Lets you define a number of Animators that will run on the attached View depending on the View's
|
||||
* drawable state.
|
||||
* <p>
|
||||
* It can be defined in an XML file with the <code><selector></code> element.
|
||||
* Each State Animator is defined in a nested <code><item></code> element.
|
||||
*
|
||||
* @attr ref android.R.styleable#DrawableStates_state_focused
|
||||
* @attr ref android.R.styleable#DrawableStates_state_window_focused
|
||||
* @attr ref android.R.styleable#DrawableStates_state_enabled
|
||||
* @attr ref android.R.styleable#DrawableStates_state_checkable
|
||||
* @attr ref android.R.styleable#DrawableStates_state_checked
|
||||
* @attr ref android.R.styleable#DrawableStates_state_selected
|
||||
* @attr ref android.R.styleable#DrawableStates_state_activated
|
||||
* @attr ref android.R.styleable#DrawableStates_state_active
|
||||
* @attr ref android.R.styleable#DrawableStates_state_single
|
||||
* @attr ref android.R.styleable#DrawableStates_state_first
|
||||
* @attr ref android.R.styleable#DrawableStates_state_middle
|
||||
* @attr ref android.R.styleable#DrawableStates_state_last
|
||||
* @attr ref android.R.styleable#DrawableStates_state_pressed
|
||||
* @attr ref android.R.styleable#StateListAnimatorItem_animation
|
||||
*/
|
||||
public class StateListAnimator {
|
||||
|
||||
private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>();
|
||||
|
||||
private Tuple mLastMatch = null;
|
||||
|
||||
private Animator mRunningAnimator = null;
|
||||
|
||||
private WeakReference<View> mViewRef;
|
||||
|
||||
private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mRunningAnimator == animation) {
|
||||
mRunningAnimator = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Associates the given animator with the provided drawable state specs so that it will be run
|
||||
* when the View's drawable state matches the specs.
|
||||
*
|
||||
* @param specs The drawable state specs to match against
|
||||
* @param animator The animator to run when the specs match
|
||||
*/
|
||||
public void addState(int[] specs, Animator animator) {
|
||||
Tuple tuple = new Tuple(specs, animator);
|
||||
tuple.mAnimator.addListener(mAnimatorListener);
|
||||
mTuples.add(tuple);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current {@link android.animation.Animator} which is started because of a state
|
||||
* change.
|
||||
*
|
||||
* @return The currently running Animator or null if no Animator is running
|
||||
* @hide
|
||||
*/
|
||||
public Animator getRunningAnimator() {
|
||||
return mRunningAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public View getTarget() {
|
||||
return mViewRef == null ? null : mViewRef.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by View
|
||||
* @hide
|
||||
*/
|
||||
public void setTarget(View view) {
|
||||
final View current = getTarget();
|
||||
if (current == view) {
|
||||
return;
|
||||
}
|
||||
if (current != null) {
|
||||
clearTarget();
|
||||
}
|
||||
if (view != null) {
|
||||
mViewRef = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void clearTarget() {
|
||||
final int size = mTuples.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
mTuples.get(i).mAnimator.setTarget(null);
|
||||
}
|
||||
|
||||
mViewRef = null;
|
||||
mLastMatch = null;
|
||||
mRunningAnimator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by View
|
||||
* @hide
|
||||
*/
|
||||
public void setState(int[] state) {
|
||||
Tuple match = null;
|
||||
final int count = mTuples.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final Tuple tuple = mTuples.get(i);
|
||||
if (StateSet.stateSetMatches(tuple.mSpecs, state)) {
|
||||
match = tuple;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match == mLastMatch) {
|
||||
return;
|
||||
}
|
||||
if (mLastMatch != null) {
|
||||
cancel(mLastMatch);
|
||||
}
|
||||
mLastMatch = match;
|
||||
if (match != null) {
|
||||
start(match);
|
||||
}
|
||||
}
|
||||
|
||||
private void start(Tuple match) {
|
||||
match.mAnimator.setTarget(getTarget());
|
||||
mRunningAnimator = match.mAnimator;
|
||||
match.mAnimator.start();
|
||||
}
|
||||
|
||||
private void cancel(Tuple lastMatch) {
|
||||
lastMatch.mAnimator.cancel();
|
||||
lastMatch.mAnimator.setTarget(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public ArrayList<Tuple> getTuples() {
|
||||
return mTuples;
|
||||
}
|
||||
|
||||
/**
|
||||
* If there is an animation running for a recent state change, ends it.
|
||||
* <p>
|
||||
* This causes the animation to assign the end value(s) to the View.
|
||||
*/
|
||||
public void jumpToCurrentState() {
|
||||
if (mRunningAnimator != null) {
|
||||
mRunningAnimator.end();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static class Tuple {
|
||||
|
||||
final int[] mSpecs;
|
||||
|
||||
final Animator mAnimator;
|
||||
|
||||
private Tuple(int[] specs, Animator animator) {
|
||||
mSpecs = specs;
|
||||
mAnimator = animator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public int[] getSpecs() {
|
||||
return mSpecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public Animator getAnimator() {
|
||||
return mAnimator;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package android.view;
|
||||
|
||||
import android.animation.AnimatorInflater;
|
||||
import android.animation.RevealAnimator;
|
||||
import android.animation.StateListAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
@@ -667,6 +669,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @attr ref android.R.styleable#View_scrollbarTrackVertical
|
||||
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawHorizontalTrack
|
||||
* @attr ref android.R.styleable#View_scrollbarAlwaysDrawVerticalTrack
|
||||
* @attr ref android.R.styleable#View_stateListAnimator
|
||||
* @attr ref android.R.styleable#View_sharedElementName
|
||||
* @attr ref android.R.styleable#View_soundEffectsEnabled
|
||||
* @attr ref android.R.styleable#View_tag
|
||||
@@ -3257,6 +3260,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
*/
|
||||
private Outline mOutline;
|
||||
|
||||
/**
|
||||
* Animator that automatically runs based on state changes.
|
||||
*/
|
||||
private StateListAnimator mStateListAnimator;
|
||||
|
||||
/**
|
||||
* When this view has focus and the next focus is {@link #FOCUS_LEFT},
|
||||
* the user may specify which view to go to next.
|
||||
@@ -3995,6 +4003,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
case R.styleable.View_nestedScrollingEnabled:
|
||||
setNestedScrollingEnabled(a.getBoolean(attr, false));
|
||||
break;
|
||||
case R.styleable.View_stateListAnimator:
|
||||
setStateListAnimator(AnimatorInflater.loadStateListAnimator(context,
|
||||
a.getResourceId(attr, 0)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10619,6 +10631,40 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
startRadius, endRadius, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current StateListAnimator if exists.
|
||||
*
|
||||
* @return StateListAnimator or null if it does not exists
|
||||
* @see #setStateListAnimator(android.animation.StateListAnimator)
|
||||
*/
|
||||
public StateListAnimator getStateListAnimator() {
|
||||
return mStateListAnimator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attaches the provided StateListAnimator to this View.
|
||||
* <p>
|
||||
* Any previously attached StateListAnimator will be detached.
|
||||
*
|
||||
* @param stateListAnimator The StateListAnimator to update the view
|
||||
* @see {@link android.animation.StateListAnimator}
|
||||
*/
|
||||
public void setStateListAnimator(StateListAnimator stateListAnimator) {
|
||||
if (mStateListAnimator == stateListAnimator) {
|
||||
return;
|
||||
}
|
||||
if (mStateListAnimator != null) {
|
||||
mStateListAnimator.setTarget(null);
|
||||
}
|
||||
mStateListAnimator = stateListAnimator;
|
||||
if (stateListAnimator != null) {
|
||||
stateListAnimator.setTarget(this);
|
||||
if (isAttachedToWindow()) {
|
||||
stateListAnimator.setState(getDrawableState());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the outline of the view, which defines the shape of the shadow it
|
||||
* casts.
|
||||
@@ -12835,7 +12881,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
destroyLayer(false);
|
||||
|
||||
cleanupDraw();
|
||||
|
||||
mCurrentAnimation = null;
|
||||
}
|
||||
|
||||
@@ -15489,9 +15534,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
/**
|
||||
* This function is called whenever the state of the view changes in such
|
||||
* a way that it impacts the state of drawables being shown.
|
||||
*
|
||||
* <p>Be sure to call through to the superclass when overriding this
|
||||
* function.
|
||||
* <p>
|
||||
* If the View has a StateListAnimator, it will also be called to run necessary state
|
||||
* change animations.
|
||||
* <p>
|
||||
* Be sure to call through to the superclass when overriding this function.
|
||||
*
|
||||
* @see Drawable#setState(int[])
|
||||
*/
|
||||
@@ -15500,6 +15547,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (d != null && d.isStateful()) {
|
||||
d.setState(getDrawableState());
|
||||
}
|
||||
|
||||
if (mStateListAnimator != null) {
|
||||
mStateListAnimator.setState(getDrawableState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -15644,11 +15695,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
/**
|
||||
* Call {@link Drawable#jumpToCurrentState() Drawable.jumpToCurrentState()}
|
||||
* on all Drawable objects associated with this view.
|
||||
* <p>
|
||||
* Also calls {@link StateListAnimator#jumpToCurrentState()} if there is a StateListAnimator
|
||||
* attached to this view.
|
||||
*/
|
||||
public void jumpDrawablesToCurrentState() {
|
||||
if (mBackground != null) {
|
||||
mBackground.jumpToCurrentState();
|
||||
}
|
||||
if (mStateListAnimator != null) {
|
||||
mStateListAnimator.jumpToCurrentState();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
34
core/res/res/anim/button_state_list_anim_quantum.xml
Normal file
34
core/res/res/anim/button_state_list_anim_quantum.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2014 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.
|
||||
-->
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:state_enabled="true">
|
||||
<set>
|
||||
<objectAnimator android:propertyName="translationZ"
|
||||
android:duration="@integer/button_pressed_animation_duration"
|
||||
android:valueTo="@dimen/button_pressed_z"
|
||||
android:valueType="floatType"/>
|
||||
</set>
|
||||
</item>
|
||||
<!-- base state -->
|
||||
<item>
|
||||
<set>
|
||||
<objectAnimator android:propertyName="translationZ"
|
||||
android:duration="@integer/button_pressed_animation_duration"
|
||||
android:valueTo="0"
|
||||
android:valueType="floatType"/>
|
||||
</set>
|
||||
</item>
|
||||
</selector>
|
||||
@@ -2364,6 +2364,9 @@
|
||||
<!-- Specifies that this view should permit nested scrolling within a compatible
|
||||
ancestor view. -->
|
||||
<attr name="nestedScrollingEnabled" format="boolean" />
|
||||
|
||||
<!-- Sets the state-based animator for the View. -->
|
||||
<attr name="stateListAnimator" format="reference"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Attributes that can be assigned to a tag for a particular View. -->
|
||||
@@ -4255,6 +4258,11 @@
|
||||
<attr name="drawable" format="reference" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Attributes that can be assigned to a StateListAnimator item. -->
|
||||
<declare-styleable name="StateListAnimatorItem">
|
||||
<attr name="animation"/>
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Drawable used to render a geometric shape, with a gradient or a solid color. -->
|
||||
<declare-styleable name="GradientDrawable">
|
||||
<!-- Indicates whether the drawable should intially be visible. -->
|
||||
|
||||
@@ -49,4 +49,7 @@
|
||||
|
||||
<dimen name="floating_window_z">16dp</dimen>
|
||||
<dimen name="floating_window_margin">32dp</dimen>
|
||||
|
||||
<!-- the amount of elevation for pressed button state-->
|
||||
<dimen name="button_pressed_z">2dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -19,4 +19,5 @@
|
||||
<resources>
|
||||
<integer name="kg_carousel_angle">75</integer>
|
||||
<integer name="kg_glowpad_rotation_offset">0</integer>
|
||||
<integer name="button_pressed_animation_duration">100</integer>
|
||||
</resources>
|
||||
|
||||
@@ -2171,6 +2171,7 @@
|
||||
<public type="attr" name="actionOverflowMenuStyle" />
|
||||
<public type="attr" name="documentLaunchMode" />
|
||||
<public type="attr" name="autoRemoveFromRecents" />
|
||||
<public type="attr" name="stateListAnimator" />
|
||||
|
||||
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
|
||||
|
||||
|
||||
@@ -364,6 +364,7 @@ please see styles_device_defaults.xml.
|
||||
<item name="textColor">?attr/textColorPrimary</item>
|
||||
<item name="minHeight">48dip</item>
|
||||
<item name="minWidth">96dip</item>
|
||||
<item name="stateListAnimator">@anim/button_state_list_anim_quantum</item>
|
||||
</style>
|
||||
|
||||
<!-- Small bordered ink button -->
|
||||
@@ -375,6 +376,7 @@ please see styles_device_defaults.xml.
|
||||
<!-- Borderless ink button -->
|
||||
<style name="Widget.Quantum.Button.Borderless">
|
||||
<item name="background">@drawable/btn_borderless_quantum</item>
|
||||
<item name="stateListAnimator">@null</item>
|
||||
</style>
|
||||
|
||||
<!-- Small borderless ink button -->
|
||||
|
||||
6
core/tests/coretests/res/anim/reset_state_anim.xml
Normal file
6
core/tests/coretests/res/anim/reset_state_anim.xml
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<set xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
|
||||
<objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
|
||||
<objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
|
||||
</set>
|
||||
19
core/tests/coretests/res/anim/test_state_anim.xml
Normal file
19
core/tests/coretests/res/anim/test_state_anim.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true">
|
||||
<set>
|
||||
<objectAnimator android:propertyName="x" android:duration="100" android:valueTo="10" android:valueType="floatType"/>
|
||||
<objectAnimator android:propertyName="y" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
|
||||
<objectAnimator android:propertyName="z" android:duration="100" android:valueTo="20" android:valueType="floatType"/>
|
||||
</set>
|
||||
</item>
|
||||
<item android:state_enabled="true" android:state_pressed="false">
|
||||
<set>
|
||||
<objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
|
||||
<objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
|
||||
<objectAnimator android:propertyName="z" android:duration="100" android:valueTo="0" android:valueType="floatType"/>
|
||||
</set>
|
||||
</item>
|
||||
<!-- base state-->
|
||||
<item android:animation="@anim/reset_state_anim"/>
|
||||
</selector>
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (C) 2014 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.animation;
|
||||
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.test.UiThreadTest;
|
||||
import android.util.StateSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
||||
public class StateListAnimatorTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
|
||||
|
||||
public StateListAnimatorTest() {
|
||||
super(BasicAnimatorActivity.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
}
|
||||
|
||||
public void testInflateFromAnimator() throws Exception {
|
||||
StateListAnimator stateListAnimator = AnimatorInflater
|
||||
.loadStateListAnimator(getActivity(), R.anim.test_state_anim);
|
||||
assertNotNull("A state list animator should be returned", stateListAnimator);
|
||||
assertEquals("State list animator should have three items", 3,
|
||||
stateListAnimator.getTuples().size());
|
||||
}
|
||||
|
||||
@UiThreadTest
|
||||
public void testAttachDetach() throws Exception {
|
||||
View view = new View(getActivity());
|
||||
final AtomicInteger setStateCount = new AtomicInteger(0);
|
||||
StateListAnimator stateListAnimator = new StateListAnimator() {
|
||||
@Override
|
||||
public void setState(int[] state) {
|
||||
setStateCount.incrementAndGet();
|
||||
super.setState(state);
|
||||
}
|
||||
};
|
||||
view.setStateListAnimator(stateListAnimator);
|
||||
assertNotNull("State list animator should have a reference to view even if it is detached",
|
||||
stateListAnimator.getTarget());
|
||||
ViewGroup viewGroup = (ViewGroup) getActivity().findViewById(android.R.id.content);
|
||||
int preSetStateCount = setStateCount.get();
|
||||
viewGroup.addView(view);
|
||||
assertTrue("When view is attached, state list drawable's setState should be called",
|
||||
preSetStateCount < setStateCount.get());
|
||||
|
||||
StateListAnimator stateListAnimator2 = new StateListAnimator();
|
||||
view.setStateListAnimator(stateListAnimator2);
|
||||
assertNull("When a new state list animator is assigned, previous one should be detached",
|
||||
stateListAnimator.getTarget());
|
||||
assertNull("Any running animator should be removed on detach",
|
||||
stateListAnimator.getRunningAnimator());
|
||||
assertEquals("The new state list animator should be attached to the view",
|
||||
view, stateListAnimator2.getTarget());
|
||||
viewGroup.removeView(view);
|
||||
assertNotNull("When view is detached from window, state list animator should still keep the"
|
||||
+ " reference",
|
||||
stateListAnimator2.getTarget());
|
||||
}
|
||||
|
||||
public void testStateListLoading() throws InterruptedException {
|
||||
StateListAnimator stateListAnimator = AnimatorInflater
|
||||
.loadStateListAnimator(getActivity(), R.anim.test_state_anim);
|
||||
assertNotNull("A state list animator should be returned", stateListAnimator);
|
||||
assertEquals("Steate list animator should have two items", 3,
|
||||
stateListAnimator.getTuples().size());
|
||||
StateListAnimator.Tuple tuple1 = stateListAnimator.getTuples().get(0);
|
||||
assertEquals("first tuple should have one state", 1, tuple1.getSpecs().length);
|
||||
assertEquals("first spec in tuple 1 should be pressed",
|
||||
com.android.internal.R.attr.state_pressed, tuple1.getSpecs()[0]);
|
||||
|
||||
StateListAnimator.Tuple tuple2 = stateListAnimator.getTuples().get(1);
|
||||
assertEquals("Second tuple should have two specs", 2, tuple2.getSpecs().length);
|
||||
assertTrue("Tuple two should match the expected state",
|
||||
StateSet.stateSetMatches(tuple2.getSpecs(),
|
||||
new int[]{-com.android.internal.R.attr.state_pressed,
|
||||
com.android.internal.R.attr.state_enabled}));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user