Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9c087440 authored by Chet Haase's avatar Chet Haase
Browse files

Supress layout requests while a LayoutTransition is running.

LayoutTransition works by animating layout-related properties
(left, right, top, and bottom). This works great when that animation
is the only thing affecting the layout of the UI. But if there are other things
happening in the application that cause layout to run on that
container or in its parent hierarchy, this can cause the layout properties
on its children to get mis-set during the middle of the transition.
This results in artifacts like animating objects jumping to locations where
they would be were there no animation running.

The fix is to supress layout requests on that container (and its children)
until the transition is complete (then issue a layout request on the container
to make sure that the container has the correct layout data)

Change-Id: I15bf0423a11409f854076f86099233db7fe4edc0
parent e9739d09
Loading
Loading
Loading
Loading
+102736 −66264

File changed.

Preview size limit exceeded, changes collapsed.

+42 −1
Original line number Diff line number Diff line
@@ -20511,6 +20511,28 @@
<parameter name="child" type="android.view.View">
</parameter>
</method>
<method name="isChangingLayout"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="isRunning"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="removeChild"
 return="void"
 abstract="false"
@@ -216454,7 +216476,7 @@
 native="false"
 synchronized="false"
 static="false"
 final="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
@@ -221085,6 +221107,25 @@
 visibility="public"
>
</method>
<method name="layout"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="l" type="int">
</parameter>
<parameter name="t" type="int">
</parameter>
<parameter name="r" type="int">
</parameter>
<parameter name="b" type="int">
</parameter>
</method>
<method name="measureChild"
 return="void"
 abstract="false"
+38 −14
Original line number Diff line number Diff line
@@ -553,9 +553,6 @@ public class LayoutTransition {
                // Make a copy of the appropriate animation
                final Animator anim = baseAnimator.clone();

                // Cache the animation in case we need to cancel it later
                currentChangingAnimations.put(child, anim);

                // Set the target object for the animation
                anim.setTarget(child);

@@ -586,6 +583,9 @@ public class LayoutTransition {
                        anim.setStartDelay(startDelay);
                        anim.setDuration(duration);

                        // Cache the animation in case we need to cancel it later
                        currentChangingAnimations.put(child, anim);

                        if (anim instanceof ObjectAnimator) {
                            ((ObjectAnimator) anim).setCurrentPlayTime(0);
                        }
@@ -657,6 +657,27 @@ public class LayoutTransition {
        });
    }

    /**
     * Returns true if animations are running which animate layout-related properties. This
     * essentially means that either CHANGE_APPEARING or CHANGE_DISAPPEARING animations
     * are running, since these animations operate on layout-related properties.
     *
     * @return true if CHANGE_APPEARING or CHANGE_DISAPPEARING animations are currently
     * running.
     */
    public boolean isChangingLayout() {
        return (currentChangingAnimations.size() > 0);
    }

    /**
     * Returns true if any of the animations in this transition are currently running.
     *
     * @return true if any animations in the transition are running.
     */
    public boolean isRunning() {
        return (currentChangingAnimations.size() > 0 || currentVisibilityAnimations.size() > 0);
    }

    /**
     * This method runs the animation that makes an added item appear.
     *
@@ -842,28 +863,31 @@ public class LayoutTransition {
    public interface TransitionListener {

        /**
         * This event is sent to listeners when an APPEARING or DISAPPEARING transition
         * begins.
         * This event is sent to listeners when any type of transition animation begins.
         *
         * @param transition The LayoutTransition sending out the event.
         * @param container The ViewGroup on which the transition is playing.
         * @param view The View object being added or removed from its parent.
         * @param transitionType The type of transition that is beginning, either
         * {@link android.animation.LayoutTransition#APPEARING} or
         * {@link android.animation.LayoutTransition#DISAPPEARING}.
         * @param view The View object being affected by the transition animation.
         * @param transitionType The type of transition that is beginning,
         * {@link android.animation.LayoutTransition#APPEARING},
         * {@link android.animation.LayoutTransition#DISAPPEARING},
         * {@link android.animation.LayoutTransition#CHANGE_APPEARING}, or
         * {@link android.animation.LayoutTransition#CHANGE_DISAPPEARING}.
         */
        public void startTransition(LayoutTransition transition, ViewGroup container,
                View view, int transitionType);

        /**
         * This event is sent to listeners when an APPEARING or DISAPPEARING transition ends.
         * This event is sent to listeners when any type of transition animation ends.
         *
         * @param transition The LayoutTransition sending out the event.
         * @param container The ViewGroup on which the transition is playing.
         * @param view The View object being added or removed from its parent.
         * @param transitionType The type of transition that is ending, either
         * {@link android.animation.LayoutTransition#APPEARING} or
         * {@link android.animation.LayoutTransition#DISAPPEARING}.
         * @param view The View object being affected by the transition animation.
         * @param transitionType The type of transition that is ending,
         * {@link android.animation.LayoutTransition#APPEARING},
         * {@link android.animation.LayoutTransition#DISAPPEARING},
         * {@link android.animation.LayoutTransition#CHANGE_APPEARING}, or
         * {@link android.animation.LayoutTransition#CHANGE_DISAPPEARING}.
         */
        public void endTransition(LayoutTransition transition, ViewGroup container,
                View view, int transitionType);
+4 −3
Original line number Diff line number Diff line
@@ -8883,11 +8883,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
     * (The first is measuring). In this phase, each parent calls
     * layout on all of its children to position them.
     * This is typically done using the child measurements
     * that were stored in the measure pass().
     * that were stored in the measure pass().</p>
     *
     * <p>Derived classes should not override this method.
     * Derived classes with children should override
     * onLayout. In that method, they should
     * call layout on each of their children.
     * call layout on each of their children.</p>
     *
     * @param l Left position, relative to parent
     * @param t Top position, relative to parent
@@ -8895,7 +8896,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
     * @param b Bottom position, relative to parent
     */
    @SuppressWarnings({"unchecked"})
    public final void layout(int l, int t, int r, int b) {
    public void layout(int l, int t, int r, int b) {
        int oldL = mLeft;
        int oldT = mTop;
        int oldB = mBottom;
+23 −0
Original line number Diff line number Diff line
@@ -318,6 +318,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
    private View[] mChildren;
    // Number of valid children in the mChildren array, the rest should be null or not
    // considered as children

    private boolean mLayoutSuppressed = false;

    private int mChildrenCount;

    private static final int ARRAY_INITIAL_CAPACITY = 12;
@@ -1828,6 +1831,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        // first send it an ACTION_CANCEL motion event.
        cancelAndClearTouchTargets(null);

        // In case view is detached while transition is running
        mLayoutSuppressed = false;

        final int count = mChildrenCount;
        final View[] children = mChildren;
        for (int i = 0; i < count; i++) {
@@ -3618,6 +3624,19 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
               (mParent == null || mParent.getChildVisibleRect(this, r, offset));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public final void layout(int l, int t, int r, int b) {
        if (mTransition == null || !mTransition.isChangingLayout()) {
            super.layout(l, t, r, b);
        } else {
            // record the fact that we noop'd it; request layout when transition finishes
            mLayoutSuppressed = true;
        }
    }

    /**
     * {@inheritDoc}
     */
@@ -4306,6 +4325,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        @Override
        public void endTransition(LayoutTransition transition, ViewGroup container,
                View view, int transitionType) {
            if (mLayoutSuppressed && !transition.isChangingLayout()) {
                requestLayout();
                mLayoutSuppressed = false;
            }
            if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
                endViewTransition(view);
            }