Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tTIMOB-15951, TIMOB-15719, TIMOB-16087: Android: Animating a child view in vertical layout no longer works correctly #5245

Merged
merged 1 commit into from
Mar 20, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public class TiAnimationBuilder
@SuppressWarnings("rawtypes")
protected HashMap options;
protected View view;
protected AnimatorHelper animatorHelper;
protected TiViewProxy viewProxy;

public TiAnimationBuilder()
Expand Down Expand Up @@ -340,6 +341,12 @@ private AnimatorSet buildPropertyAnimators(int x, int y, int w, int h, int paren
}

if (tdm != null) {
AnimatorUpdateListener updateListener = null;
// Need to invalidate the parent view for Honeycomb+. Otherwise it will not draw correctly.
if (!PRE_HONEYCOMB) {
updateListener = new AnimatorUpdateListener();
}

// Derive a set of property Animators from the
// operations in the matrix so we can go ahead
// and use Honeycomb+ animations rather than
Expand Down Expand Up @@ -369,26 +376,46 @@ private AnimatorSet buildPropertyAnimators(int x, int y, int w, int h, int paren
case Operation.TYPE_ROTATE:
includesRotation = true;
if (operation.rotationFromValueSpecified) {
addAnimator(animators, ObjectAnimator.ofFloat(view, "rotation", operation.rotateFrom,
operation.rotateTo));
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "rotation", operation.rotateFrom,
operation.rotateTo);
if (updateListener != null) {
anim.addUpdateListener(updateListener);
}
addAnimator(animators, anim);
} else {
addAnimator(animators, ObjectAnimator.ofFloat(view, "rotation", operation.rotateTo));
ObjectAnimator anim = ObjectAnimator.ofFloat(view, "rotation", operation.rotateTo);
if (updateListener != null) {
anim.addUpdateListener(updateListener);
}
addAnimator(animators, anim);
}
break;
case Operation.TYPE_SCALE:
if (operation.scaleFromValuesSpecified) {
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleX", operation.scaleFromX,
operation.scaleToX));
ObjectAnimator animX = ObjectAnimator.ofFloat(view, "scaleX", operation.scaleFromX,
operation.scaleToX);
if (updateListener != null) {
animX.addUpdateListener(updateListener);
}
addAnimator(animators, animX);
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleY", operation.scaleFromY,
operation.scaleToY));

} else {
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleX", operation.scaleToX));
ObjectAnimator animX = ObjectAnimator.ofFloat(view, "scaleX", operation.scaleToX);
if (updateListener != null) {
animX.addUpdateListener(updateListener);
}
addAnimator(animators, animX);
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleY", operation.scaleToY));
}
break;
case Operation.TYPE_TRANSLATE:
addAnimator(animators, ObjectAnimator.ofFloat(view, "translationX", operation.translateX));
ObjectAnimator animX = ObjectAnimator.ofFloat(view, "translationX", operation.translateX);
if (updateListener != null) {
animX.addUpdateListener(updateListener);
}
addAnimator(animators, animX);
addAnimator(animators, ObjectAnimator.ofFloat(view, "translationY", operation.translateY));
}
}
Expand Down Expand Up @@ -449,11 +476,25 @@ private AnimatorSet buildPropertyAnimators(int x, int y, int w, int h, int paren
TiCompositeLayout.computePosition(parentView, optionTop, optionCenterY, optionBottom, h, 0, parentHeight,
vertical);

int translationX = horizontal[0] - x;
int translationY = vertical[0] - y;
// For pre-Honeycomb, there will be flicker during animation if using animatorHelper.
if (PRE_HONEYCOMB) {
int translationX = horizontal[0] - x;
int translationY = vertical[0] - y;
addAnimator(animators, ObjectAnimator.ofFloat(view, "translationX", translationX));
addAnimator(animators, ObjectAnimator.ofFloat(view, "translationY", translationY));

addAnimator(animators, ObjectAnimator.ofFloat(view, "translationX", translationX));
addAnimator(animators, ObjectAnimator.ofFloat(view, "translationY", translationY));
// For Honeycomb+, animatorHelper will reset layout parameters so the layout will keep correct (TIMOB-15951).
} else {
if (animatorHelper == null) {
animatorHelper = new AnimatorHelper();
}
if (left != null || right != null || centerX != null) {
addAnimator(animators, ObjectAnimator.ofInt(animatorHelper, "left", x, horizontal[0]));
}
if (top != null || bottom != null || centerY != null) {
addAnimator(animators, ObjectAnimator.ofInt(animatorHelper, "top", y, vertical[0]));
}
}

// Pre-Honeycomb, we will need to update layout params at end of
// animation so that touch events will be recognized at new location,
Expand All @@ -466,7 +507,6 @@ private AnimatorSet buildPropertyAnimators(int x, int y, int w, int h, int paren
}

if (tdm == null && (width != null || height != null)) {
// A Scale animation *not* done via the 2DMatrix.
TiDimension optionWidth, optionHeight;

if (width != null) {
Expand All @@ -491,38 +531,26 @@ private AnimatorSet buildPropertyAnimators(int x, int y, int w, int h, int paren
int toWidth = optionWidth.getAsPixels(parentView != null ? parentView : view);
int toHeight = optionHeight.getAsPixels(parentView != null ? parentView : view);

float scaleX = (float) toWidth / w;
float scaleY = (float) toHeight / h;
// For pre-Honeycomb, there will be flicker during animation if using animatorHelper.
if (PRE_HONEYCOMB) {
float scaleX = (float) toWidth / w;
float scaleY = (float) toHeight / h;
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleX", scaleX));
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleY", scaleY));

// On Honeycomb+, if the original width/height is 0, we need to set width to a non-zero value so it can be scaled.
if (!PRE_HONEYCOMB && (w == 0 || h == 0)) {
ViewGroup.LayoutParams params = view.getLayoutParams();
TiCompositeLayout.LayoutParams tiParams = null;
if (params instanceof TiCompositeLayout.LayoutParams) {
tiParams = (TiCompositeLayout.LayoutParams) params;
// For Honeycomb+, animatorHelper will reset layout parameters so the layout will keep correct (TIMOB-15951, TIMOB-16087).
} else {
if (animatorHelper == null) {
animatorHelper = new AnimatorHelper();
}
if (w == 0) {
params.width = 1;
scaleX = (float) toWidth;
if (tiParams != null) {
tiParams.optionWidth = new TiDimension(1, TiDimension.TYPE_WIDTH);
tiParams.optionWidth.setUnits(TypedValue.COMPLEX_UNIT_PX);
}
if (width != null) {
addAnimator(animators, ObjectAnimator.ofInt(animatorHelper, "width", w, toWidth));
}
if (h == 0) {
params.height = 1;
scaleY = (float) toHeight;
if (tiParams != null) {
tiParams.optionHeight = new TiDimension(1, TiDimension.TYPE_WIDTH);
tiParams.optionHeight.setUnits(TypedValue.COMPLEX_UNIT_PX);
}
if (height != null) {
addAnimator(animators, ObjectAnimator.ofInt(animatorHelper, "height", h, toHeight));
}
view.setLayoutParams(params);
}

addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleX", scaleX));
addAnimator(animators, ObjectAnimator.ofFloat(view, "scaleY", scaleY));

setAnchor(w, h);

// Pre-Honeycomb, will need to update layout params at end of
Expand Down Expand Up @@ -604,8 +632,6 @@ private void setViewPivotHC(float pivotX, float pivotY)
{
view.setPivotX(pivotX);
view.setPivotY(pivotY);
//invalidate the view to update the canvas after setting pivots [TIMOB-2373].
view.invalidate();
}

private void setViewPivot(float pivotX, float pivotY)
Expand Down Expand Up @@ -1075,6 +1101,95 @@ public void onAnimationEnd(Animation animation)
}
}

/**
* A helper class for Honeycomb+ Property Animators to animate width/height/top/bottom/left/right/center.
* Based on the Android doc http://developer.android.com/guide/topics/graphics/prop-animation.html, to have
* the ObjectAnimator update properties correctly, the property must have a setter function.
*/
protected class AnimatorHelper
{
public void setWidth(final int w)
{
ViewGroup.LayoutParams params = view.getLayoutParams();
params.width = w;

if (params instanceof TiCompositeLayout.LayoutParams) {
TiCompositeLayout.LayoutParams tiParams = (TiCompositeLayout.LayoutParams) params;
tiParams.optionWidth = new TiDimension(w, TiDimension.TYPE_WIDTH);
tiParams.optionWidth.setUnits(TypedValue.COMPLEX_UNIT_PX);
}

view.setLayoutParams(params);
ViewParent vp = view.getParent();
if (vp instanceof View) {
// Need to invalidate the parent view. Otherwise, it will not draw correctly.
((View) vp).invalidate();
}
}

public void setHeight(final int h)
{
ViewGroup.LayoutParams params = view.getLayoutParams();
params.height = h;

if (params instanceof TiCompositeLayout.LayoutParams) {
TiCompositeLayout.LayoutParams tiParams = (TiCompositeLayout.LayoutParams) params;
tiParams.optionHeight = new TiDimension(h, TiDimension.TYPE_HEIGHT);
tiParams.optionHeight.setUnits(TypedValue.COMPLEX_UNIT_PX);
}

view.setLayoutParams(params);
ViewParent vp = view.getParent();
if (vp instanceof View) {
((View) vp).invalidate();
}
}

public void setLeft(final int l)
{
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof TiCompositeLayout.LayoutParams) {
TiCompositeLayout.LayoutParams tiParams = (TiCompositeLayout.LayoutParams) params;
tiParams.optionLeft = new TiDimension(l, TiDimension.TYPE_LEFT);
tiParams.optionLeft.setUnits(TypedValue.COMPLEX_UNIT_PX);
}
view.requestLayout();
ViewParent vp = view.getParent();
if (vp instanceof View) {
((View) vp).invalidate();
}
}

public void setTop(final int t)
{
ViewGroup.LayoutParams params = view.getLayoutParams();
if (params instanceof TiCompositeLayout.LayoutParams) {
TiCompositeLayout.LayoutParams tiParams = (TiCompositeLayout.LayoutParams) params;
tiParams.optionTop = new TiDimension(t, TiDimension.TYPE_TOP);
tiParams.optionTop.setUnits(TypedValue.COMPLEX_UNIT_PX);
}
view.requestLayout();
ViewParent vp = view.getParent();
if (vp instanceof View) {
((View) vp).invalidate();
}
}
}

/**
* The listener to receive callbacks on every animation frame.
*/
protected class AnimatorUpdateListener implements ValueAnimator.AnimatorUpdateListener
{
public void onAnimationUpdate(ValueAnimator animation)
{
ViewParent vp = view.getParent();
if (vp instanceof View) {
((View) vp).invalidate();
}
}
}

/**
* The listener for Honeycomb+ property Animators.
*/
Expand Down