Added the possibility to animate X and refactoring

A viewstate can now animate its X value.
This also refactors the animation logic such that
an application when an animation is running will
update the existing animation nicely.

Test: manual, observe views animating in X
Bug: 32437839
Change-Id: Ic091d87e530af793281ca3f2b1e9370ff5dac236
This commit is contained in:
Selim Cinek
2016-11-08 09:52:52 -08:00
parent d127d79231
commit c40c79ac66
4 changed files with 143 additions and 10 deletions

View File

@@ -16,18 +16,21 @@
-->
<resources>
<item type="id" name="translation_x_animator_tag"/>
<item type="id" name="translation_y_animator_tag"/>
<item type="id" name="translation_z_animator_tag"/>
<item type="id" name="alpha_animator_tag"/>
<item type="id" name="top_inset_animator_tag"/>
<item type="id" name="height_animator_tag"/>
<item type="id" name="shadow_alpha_animator_tag"/>
<item type="id" name="translation_x_animator_end_value_tag"/>
<item type="id" name="translation_y_animator_end_value_tag"/>
<item type="id" name="translation_z_animator_end_value_tag"/>
<item type="id" name="alpha_animator_end_value_tag"/>
<item type="id" name="top_inset_animator_end_value_tag"/>
<item type="id" name="height_animator_end_value_tag"/>
<item type="id" name="shadow_alpha_animator_end_value_tag"/>
<item type="id" name="translation_x_animator_start_value_tag"/>
<item type="id" name="translation_y_animator_start_value_tag"/>
<item type="id" name="translation_z_animator_start_value_tag"/>
<item type="id" name="alpha_animator_start_value_tag"/>

View File

@@ -23,6 +23,7 @@ import java.util.ArrayList;
*/
public class AnimationFilter {
boolean animateAlpha;
boolean animateX;
boolean animateY;
boolean animateZ;
boolean animateHeight;
@@ -42,6 +43,11 @@ public class AnimationFilter {
return this;
}
public AnimationFilter animateX() {
animateX = true;
return this;
}
public AnimationFilter animateY() {
animateY = true;
return this;
@@ -116,6 +122,7 @@ public class AnimationFilter {
private void combineFilter(AnimationFilter filter) {
animateAlpha |= filter.animateAlpha;
animateX |= filter.animateX;
animateY |= filter.animateY;
animateZ |= filter.animateZ;
animateHeight |= filter.animateHeight;
@@ -129,6 +136,7 @@ public class AnimationFilter {
private void reset() {
animateAlpha = false;
animateX = false;
animateY = false;
animateZ = false;
animateHeight = false;

View File

@@ -32,7 +32,7 @@ public class AnimationProperties {
* @return an animation filter for this animation.
*/
public AnimationFilter getAnimationFilter() {
return null;
return new AnimationFilter();
}
/**
@@ -49,7 +49,17 @@ public class AnimationProperties {
/**
* Get a custom interpolator for a property instead of the normal one.
*/
public Interpolator getCustomInterpolator(View child, Property translationY) {
public Interpolator getCustomInterpolator(View child, Property property) {
return null;
}
public AnimationProperties setDuration(long duration) {
this.duration = duration;
return this;
}
public AnimationProperties setDelay(long delay) {
this.delay = delay;
return this;
}
}

View File

@@ -36,12 +36,26 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
*/
public class ViewState {
/**
* Some animation properties that can be used to update running animations but not creating
* any new ones.
*/
protected static final AnimationProperties NO_NEW_ANIMATIONS = new AnimationProperties() {
AnimationFilter mAnimationFilter = new AnimationFilter();
@Override
public AnimationFilter getAnimationFilter() {
return mAnimationFilter;
}
};
private static final int TAG_ANIMATOR_TRANSLATION_X = R.id.translation_x_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
private static final int TAG_ANIMATOR_ALPHA = R.id.alpha_animator_tag;
private static final int TAG_END_TRANSLATION_X = R.id.translation_x_animator_end_value_tag;
private static final int TAG_END_TRANSLATION_Y = R.id.translation_y_animator_end_value_tag;
private static final int TAG_END_TRANSLATION_Z = R.id.translation_z_animator_end_value_tag;
private static final int TAG_END_ALPHA = R.id.alpha_animator_end_value_tag;
private static final int TAG_START_TRANSLATION_X = R.id.translation_x_animator_start_value_tag;
private static final int TAG_START_TRANSLATION_Y = R.id.translation_y_animator_start_value_tag;
private static final int TAG_START_TRANSLATION_Z = R.id.translation_z_animator_start_value_tag;
private static final int TAG_START_ALPHA = R.id.alpha_animator_start_value_tag;
@@ -86,7 +100,10 @@ public class ViewState {
return;
}
boolean becomesInvisible = this.alpha == 0.0f || this.hidden;
if (view.getAlpha() != this.alpha) {
boolean animatingAlpha = isAnimating(view, TAG_ANIMATOR_ALPHA);
if (animatingAlpha) {
updateAlphaAnimation(view);
} else if (view.getAlpha() != this.alpha) {
// apply layer type
boolean becomesFullyVisible = this.alpha == 1.0f;
boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible
@@ -114,17 +131,26 @@ public class ViewState {
}
// apply xTranslation
if (view.getTranslationX() != this.xTranslation) {
boolean animatingX = isAnimating(view, TAG_ANIMATOR_TRANSLATION_X);
if (animatingX) {
updateAnimationX(view);
} else if (view.getTranslationX() != this.xTranslation){
view.setTranslationX(this.xTranslation);
}
// apply yTranslation
if (view.getTranslationY() != this.yTranslation) {
boolean animatingY = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Y);
if (animatingY) {
updateAnimationY(view);
} else if (view.getTranslationY() != this.yTranslation) {
view.setTranslationY(this.yTranslation);
}
// apply zTranslation
if (view.getTranslationZ() != this.zTranslation) {
boolean animatingZ = isAnimating(view, TAG_ANIMATOR_TRANSLATION_Z);
if (animatingZ) {
updateAnimationZ(view);
} else if (view.getTranslationZ() != this.zTranslation) {
view.setTranslationZ(this.zTranslation);
}
@@ -139,6 +165,10 @@ public class ViewState {
}
}
private boolean isAnimating(View view, int tag) {
return getChildTag(view, tag) != null;
}
/**
* Start an animation to this viewstate
* @param child the view to animate
@@ -151,8 +181,6 @@ public class ViewState {
&& !this.gone && !this.hidden) {
child.setVisibility(View.VISIBLE);
}
boolean yTranslationChanging = child.getTranslationY() != this.yTranslation;
boolean zTranslationChanging = child.getTranslationZ() != this.zTranslation;
float childAlpha = child.getAlpha();
boolean alphaChanging = this.alpha != childAlpha;
if (child instanceof ExpandableView) {
@@ -160,15 +188,22 @@ public class ViewState {
alphaChanging &= !((ExpandableView) child).willBeGone();
}
// start translationX animation
if (child.getTranslationX() != this.xTranslation) {
startXTranslationAnimation(child, animationProperties);
} else {
abortAnimation(child, TAG_ANIMATOR_TRANSLATION_X);
}
// start translationY animation
if (yTranslationChanging) {
if (child.getTranslationY() != this.yTranslation) {
startYTranslationAnimation(child, animationProperties);
} else {
abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Y);
}
// start translationZ animation
if (zTranslationChanging) {
if (child.getTranslationZ() != this.zTranslation) {
startZTranslationAnimation(child, animationProperties);
} else {
abortAnimation(child, TAG_ANIMATOR_TRANSLATION_Z);
@@ -182,6 +217,10 @@ public class ViewState {
}
}
private void updateAlphaAnimation(View view) {
startAlphaAnimation(view, NO_NEW_ANIMATIONS);
}
private void startAlphaAnimation(final View child, AnimationProperties properties) {
Float previousStartValue = getChildTag(child,TAG_START_ALPHA);
Float previousEndValue = getChildTag(child,TAG_END_ALPHA);
@@ -260,6 +299,10 @@ public class ViewState {
child.setTag(TAG_END_ALPHA, newEndValue);
}
private void updateAnimationZ(View view) {
startZTranslationAnimation(view, NO_NEW_ANIMATIONS);
}
private void startZTranslationAnimation(final View child, AnimationProperties properties) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Z);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Z);
@@ -316,6 +359,75 @@ public class ViewState {
child.setTag(TAG_END_TRANSLATION_Z, newEndValue);
}
private void updateAnimationX(View view) {
startXTranslationAnimation(view, NO_NEW_ANIMATIONS);
}
private void startXTranslationAnimation(final View child, AnimationProperties properties) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_X);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_X);
float newEndValue = this.xTranslation;
if (previousEndValue != null && previousEndValue == newEndValue) {
return;
}
ObjectAnimator previousAnimator = getChildTag(child, TAG_ANIMATOR_TRANSLATION_X);
AnimationFilter filter = properties.getAnimationFilter();
if (!filter.animateX) {
// just a local update was performed
if (previousAnimator != null) {
// we need to increase all animation keyframes of the previous animator by the
// relative change to the end value
PropertyValuesHolder[] values = previousAnimator.getValues();
float relativeDiff = newEndValue - previousEndValue;
float newStartValue = previousStartValue + relativeDiff;
values[0].setFloatValues(newStartValue, newEndValue);
child.setTag(TAG_START_TRANSLATION_X, newStartValue);
child.setTag(TAG_END_TRANSLATION_X, newEndValue);
previousAnimator.setCurrentPlayTime(previousAnimator.getCurrentPlayTime());
return;
} else {
// no new animation needed, let's just apply the value
child.setTranslationX(newEndValue);
return;
}
}
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_X,
child.getTranslationX(), newEndValue);
Interpolator customInterpolator = properties.getCustomInterpolator(child,
View.TRANSLATION_X);
Interpolator interpolator = customInterpolator != null ? customInterpolator
: Interpolators.FAST_OUT_SLOW_IN;
animator.setInterpolator(interpolator);
long newDuration = cancelAnimatorAndGetNewDuration(properties.duration, previousAnimator);
animator.setDuration(newDuration);
if (properties.delay > 0 && (previousAnimator == null
|| previousAnimator.getAnimatedFraction() == 0)) {
animator.setStartDelay(properties.delay);
}
AnimatorListenerAdapter listener = properties.getAnimationFinishListener();
if (listener != null) {
animator.addListener(listener);
}
// remove the tag when the animation is finished
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
child.setTag(TAG_ANIMATOR_TRANSLATION_X, null);
child.setTag(TAG_START_TRANSLATION_X, null);
child.setTag(TAG_END_TRANSLATION_X, null);
}
});
startAnimator(animator, listener);
child.setTag(TAG_ANIMATOR_TRANSLATION_X, animator);
child.setTag(TAG_START_TRANSLATION_X, child.getTranslationX());
child.setTag(TAG_END_TRANSLATION_X, newEndValue);
}
private void updateAnimationY(View view) {
startYTranslationAnimation(view, NO_NEW_ANIMATIONS);
}
private void startYTranslationAnimation(final View child, AnimationProperties properties) {
Float previousStartValue = getChildTag(child,TAG_START_TRANSLATION_Y);
Float previousEndValue = getChildTag(child,TAG_END_TRANSLATION_Y);