diff options
author | Kevin <kevhan@google.com> | 2019-04-10 14:04:43 -0700 |
---|---|---|
committer | Kevin <kevhan@google.com> | 2019-04-23 09:26:52 -0700 |
commit | fbe9182b7502df6ed8db0446130cdde53bc84095 (patch) | |
tree | abc57303df8d3e032ef31e1f675022d4c73e16d3 /go/quickstep/src | |
parent | 6092a6ee1ef6a129525ab09acd008ce4d78add0a (diff) | |
download | android_packages_apps_Trebuchet-fbe9182b7502df6ed8db0446130cdde53bc84095.tar.gz android_packages_apps_Trebuchet-fbe9182b7502df6ed8db0446130cdde53bc84095.tar.bz2 android_packages_apps_Trebuchet-fbe9182b7502df6ed8db0446130cdde53bc84095.zip |
Change layout anim from Animation => Animator
Change the layout animation to use animators instead of the built-in
animation-based layout animation. Animator-based animations are more
flexible and can act on the view properties themselves, making it
easier to deal with if we need to cancel the animation later from a
conflicting animation (i.e. we find out we need to animate a view
out).
Bug: 114136250
Test: Go to recents, see items animate in
Change-Id: Id8227cd50e81999cac98912ac58cd2d6864c40af
(cherry picked from commit 26ad999b10c35a28585ffd3a5928d90446379c95)
Diffstat (limited to 'go/quickstep/src')
-rw-r--r-- | go/quickstep/src/com/android/quickstep/views/IconRecentsView.java | 91 |
1 files changed, 71 insertions, 20 deletions
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java index c06b6ec41..7f77b6cc4 100644 --- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java +++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java @@ -24,14 +24,12 @@ import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; import android.content.Context; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.FloatProperty; import android.view.View; import android.view.ViewDebug; -import android.view.animation.AlphaAnimation; -import android.view.animation.Animation; -import android.view.animation.AnimationSet; -import android.view.animation.LayoutAnimationController; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import androidx.annotation.NonNull; @@ -40,6 +38,7 @@ import androidx.recyclerview.widget.ItemTouchHelper; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver; +import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener; import com.android.launcher3.R; import com.android.quickstep.RecentsToActivityHelper; @@ -90,7 +89,6 @@ public final class IconRecentsView extends FrameLayout { private final TaskListLoader mTaskLoader; private final TaskAdapter mTaskAdapter; private final TaskActionController mTaskActionController; - private final LayoutAnimationController mLayoutAnimation; private RecentsToActivityHelper mActivityHelper; private RecyclerView mTaskRecyclerView; @@ -98,6 +96,9 @@ public final class IconRecentsView extends FrameLayout { private View mContentView; private View mClearAllView; private boolean mTransitionedFromApp; + private AnimatorSet mLayoutAnimation; + private final ArraySet<View> mLayingOutViews = new ArraySet<>(); + public IconRecentsView(Context context, AttributeSet attrs) { super(context, attrs); @@ -106,7 +107,6 @@ public final class IconRecentsView extends FrameLayout { mTaskAdapter = new TaskAdapter(mTaskLoader); mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter); mTaskAdapter.setActionController(mTaskActionController); - mLayoutAnimation = createLayoutAnimation(); } @Override @@ -120,7 +120,20 @@ public final class IconRecentsView extends FrameLayout { ItemTouchHelper helper = new ItemTouchHelper( new TaskSwipeCallback(mTaskActionController)); helper.attachToRecyclerView(mTaskRecyclerView); - mTaskRecyclerView.setLayoutAnimation(mLayoutAnimation); + mTaskRecyclerView.addOnChildAttachStateChangeListener( + new OnChildAttachStateChangeListener() { + @Override + public void onChildViewAttachedToWindow(@NonNull View view) { + if (mLayoutAnimation != null && !mLayingOutViews.contains(view)) { + // Child view was added that is not part of current layout animation + // so restart the animation. + animateFadeInLayoutAnimation(); + } + } + + @Override + public void onChildViewDetachedFromWindow(@NonNull View view) { } + }); mEmptyView = findViewById(R.id.recent_task_empty_view); mContentView = findViewById(R.id.recent_task_content_view); @@ -165,8 +178,7 @@ public final class IconRecentsView extends FrameLayout { * becomes visible. */ public void onBeginTransitionToOverview() { - mTaskRecyclerView.scheduleLayoutAnimation(); - + scheduleFadeInLayoutAnimation(); // Load any task changes if (!mTaskLoader.needsToLoad()) { return; @@ -338,17 +350,56 @@ public final class IconRecentsView extends FrameLayout { }); } - private static LayoutAnimationController createLayoutAnimation() { - AnimationSet anim = new AnimationSet(false /* shareInterpolator */); - - Animation alphaAnim = new AlphaAnimation(0, 1); - alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION); - anim.addAnimation(alphaAnim); - - LayoutAnimationController layoutAnim = new LayoutAnimationController(anim); - layoutAnim.setDelay( - (float) LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN / LAYOUT_ITEM_ANIMATE_IN_DURATION); + /** + * Schedule a one-shot layout animation on the next layout. Separate from + * {@link #scheduleLayoutAnimation()} as the animation is {@link Animator} based and acts on the + * view properties themselves, allowing more controllable behavior and making it easier to + * manage when the animation conflicts with another animation. + */ + private void scheduleFadeInLayoutAnimation() { + ViewTreeObserver viewTreeObserver = mTaskRecyclerView.getViewTreeObserver(); + viewTreeObserver.addOnGlobalLayoutListener( + new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + animateFadeInLayoutAnimation(); + viewTreeObserver.removeOnGlobalLayoutListener(this); + } + }); + } - return layoutAnim; + /** + * Start animating the layout animation where items fade in. + */ + private void animateFadeInLayoutAnimation() { + if (mLayoutAnimation != null) { + // If layout animation still in progress, cancel and restart. + mLayoutAnimation.cancel(); + } + TaskItemView[] views = getTaskViews(); + int delay = 0; + mLayoutAnimation = new AnimatorSet(); + for (TaskItemView view : views) { + view.setAlpha(0.0f); + Animator alphaAnim = ObjectAnimator.ofFloat(view, ALPHA, 0.0f, 1.0f); + alphaAnim.setDuration(LAYOUT_ITEM_ANIMATE_IN_DURATION).setStartDelay(delay); + alphaAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + view.setAlpha(1.0f); + mLayingOutViews.remove(view); + } + }); + delay += LAYOUT_ITEM_ANIMATE_IN_DELAY_BETWEEN; + mLayoutAnimation.play(alphaAnim); + mLayingOutViews.add(view); + } + mLayoutAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mLayoutAnimation = null; + } + }); + mLayoutAnimation.start(); } } |