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 android.support.v17.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 * android.support.v17.leanback.transition.TranslationAnimationCreator which is hidden. 33 */ 34 // Copied from android.support.v17.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 */ 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 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 108 public void onAnimationCancel(Animator animation) { 109 mTransitionPosition = Math.round(mStartX + mMovingView.getTranslationX()); 110 mViewInHierarchy.setTag(R.id.transitionPosition, mTransitionPosition); 111 } 112 113 @Override 114 public void onAnimationEnd(Animator animator) {} 115 116 @Override 117 public void onAnimationPause(Animator animator) { 118 mPausedX = mMovingView.getTranslationX(); 119 mMovingView.setTranslationX(mTerminalX); 120 } 121 122 @Override 123 public void onAnimationResume(Animator animator) { 124 mMovingView.setTranslationX(mPausedX); 125 } 126 127 @Override 128 public void onTransitionStart(Transition transition) {} 129 130 @Override 131 public void onTransitionEnd(Transition transition) { 132 mMovingView.setTranslationX(mTerminalX); 133 } 134 135 @Override 136 public void onTransitionCancel(Transition transition) {} 137 138 @Override 139 public void onTransitionPause(Transition transition) {} 140 141 @Override 142 public void onTransitionResume(Transition transition) {} 143 } 144 } 145