1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tv.common.ui.setup.animation; 17 18 import android.animation.Animator; 19 import android.animation.AnimatorListenerAdapter; 20 import android.animation.ObjectAnimator; 21 import android.animation.TimeInterpolator; 22 import android.graphics.Path; 23 import androidx.leanback.R; 24 import android.transition.Transition; 25 import android.transition.TransitionValues; 26 import android.view.View; 27 28 /** 29 * This class is used by Slide and Explode to create an animator that goes from the start position 30 * to the end position. It takes into account the canceled position so that it will not blink out or 31 * shift suddenly when the transition is interrupted. The original class is 32 * androidx.leanback.transition.TranslationAnimationCreator which is hidden. 33 */ 34 // Copied from androidx.leanback.transition.TransltaionAnimationCreator 35 class TranslationAnimationCreator { 36 /** 37 * Creates an animator that can be used for x and/or y translations. When interrupted, it sets a 38 * tag to keep track of the position so that it may be continued from position. 39 * 40 * @param view The view being moved. This may be in the overlay for onDisappear. 41 * @param values The values containing the view in the view hierarchy. 42 * @param viewPosX The x screen coordinate of view 43 * @param startX The start translation x of view 44 * @param endX The end translation x of view 45 * @param interpolator The interpolator to use with this animator. 46 * @return An animator that moves from (startX, startY) to (endX, endY) unless there was a 47 * previous interruption, in which case it moves from the current position to (endX, endY). 48 */ createAnimation( View view, TransitionValues values, int viewPosX, float startX, float endX, TimeInterpolator interpolator, Transition transition)49 static Animator createAnimation( 50 View view, 51 TransitionValues values, 52 int viewPosX, 53 float startX, 54 float endX, 55 TimeInterpolator interpolator, 56 Transition transition) { 57 float terminalX = view.getTranslationX(); 58 Integer startPosition = (Integer) values.view.getTag(R.id.transitionPosition); 59 if (startPosition != null) { 60 startX = startPosition - viewPosX + terminalX; 61 } 62 // Initial position is at translation startX, startY, so position is offset by that 63 // amount 64 int startPosX = viewPosX + Math.round(startX - terminalX); 65 66 view.setTranslationX(startX); 67 if (startX == endX) { 68 return null; 69 } 70 Path path = new Path(); 71 path.moveTo(startX, 0); 72 path.lineTo(endX, 0); 73 ObjectAnimator anim = 74 ObjectAnimator.ofFloat(view, View.TRANSLATION_X, View.TRANSLATION_Y, path); 75 76 TransitionPositionListener listener = 77 new TransitionPositionListener(view, values.view, startPosX, terminalX); 78 transition.addListener(listener); 79 anim.addListener(listener); 80 anim.addPauseListener(listener); 81 anim.setInterpolator(interpolator); 82 return anim; 83 } 84 85 private static class TransitionPositionListener extends AnimatorListenerAdapter 86 implements Transition.TransitionListener { 87 88 private final View mViewInHierarchy; 89 private final View mMovingView; 90 private final int mStartX; 91 private Integer mTransitionPosition; 92 private float mPausedX; 93 private final float mTerminalX; 94 TransitionPositionListener( View movingView, View viewInHierarchy, int startX, float terminalX)95 private TransitionPositionListener( 96 View movingView, View viewInHierarchy, int startX, float terminalX) { 97 mMovingView = movingView; 98 mViewInHierarchy = viewInHierarchy; 99 mStartX = startX - Math.round(mMovingView.getTranslationX()); 100 mTerminalX = terminalX; 101 mTransitionPosition = (Integer) mViewInHierarchy.getTag(R.id.transitionPosition); 102 if (mTransitionPosition != null) { 103 mViewInHierarchy.setTag(R.id.transitionPosition, null); 104 } 105 } 106 107 @Override onAnimationCancel(Animator animation)108 public void onAnimationCancel(Animator animation) { 109 mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX()); 110 mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition); 111 } 112 113 @Override onAnimationEnd(Animator animator)114 public void onAnimationEnd(Animator animator) {} 115 116 @Override onAnimationPause(Animator animator)117 public void onAnimationPause(Animator animator) { 118 mPausedX = mMovingView.getTranslationX(); 119 mMovingView.setTranslationX(mTerminalX); 120 } 121 122 @Override onAnimationResume(Animator animator)123 public void onAnimationResume(Animator animator) { 124 mMovingView.setTranslationX(mPausedX); 125 } 126 127 @Override onTransitionStart(Transition transition)128 public void onTransitionStart(Transition transition) {} 129 130 @Override onTransitionEnd(Transition transition)131 public void onTransitionEnd(Transition transition) { 132 mMovingView.setTranslationX(mTerminalX); 133 } 134 135 @Override onTransitionCancel(Transition transition)136 public void onTransitionCancel(Transition transition) {} 137 138 @Override onTransitionPause(Transition transition)139 public void onTransitionPause(Transition transition) {} 140 141 @Override onTransitionResume(Transition transition)142 public void onTransitionResume(Transition transition) {} 143 } 144 } 145