107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko/* 207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Copyright (C) 2015 The Android Open Source Project 307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * you may not use this file except in compliance with the License. 607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * You may obtain a copy of the License at 707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * http://www.apache.org/licenses/LICENSE-2.0 907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 1007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Unless required by applicable law or agreed to in writing, software 1107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 1207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * See the License for the specific language governing permissions and 1407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * limitations under the License. 1507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 1607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 1707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkopackage com.android.tv.menu; 1807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 1907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.animation.Animator; 2007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.animation.AnimatorListenerAdapter; 2107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.animation.AnimatorSet; 2207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.animation.ObjectAnimator; 2307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.animation.TimeInterpolator; 2407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.content.Context; 2507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.content.res.Resources; 2607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.graphics.Rect; 2707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.support.annotation.UiThread; 2807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.support.v4.view.animation.FastOutLinearInInterpolator; 2907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.support.v4.view.animation.FastOutSlowInInterpolator; 3007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.support.v4.view.animation.LinearOutSlowInInterpolator; 3107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.util.Log; 3207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.util.Property; 3307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.view.View; 3407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.view.ViewGroup.MarginLayoutParams; 3507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport android.widget.TextView; 3607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 3707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport com.android.tv.R; 3848dadb49248271b01997862e1335912a4f2e189fYoungsang Choimport com.android.tv.common.SoftPreconditions; 3907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport com.android.tv.util.Utils; 4007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 4107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.ArrayList; 4207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.Collections; 4307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.HashMap; 4407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.List; 4507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.Map; 4607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.Map.Entry; 4707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkoimport java.util.concurrent.TimeUnit; 4807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 4907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko/** 5007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * A view that represents TV main menu. 5107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 5207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko@UiThread 5307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalkopublic class MenuLayoutManager { 5407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko static final String TAG = "MenuLayoutManager"; 5507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko static final boolean DEBUG = false; 5607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 5707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The visible duration of the title before it is hidden. 5807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private static final long TITLE_SHOW_DURATION_BEFORE_HIDDEN_MS = TimeUnit.SECONDS.toMillis(2); 5907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 6007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final MenuView mMenuView; 6107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final List<MenuRow> mMenuRows = new ArrayList<>(); 6207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final List<MenuRowView> mMenuRowViews = new ArrayList<>(); 6307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final List<Integer> mRemovingRowViews = new ArrayList<>(); 6407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private int mSelectedPosition = -1; 6507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 6607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mRowAlignFromBottom; 6707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mRowContentsPaddingTop; 6807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mRowContentsPaddingBottomMax; 6907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mRowTitleTextDescenderHeight; 7007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mMenuMarginBottomMin; 7107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mRowTitleHeight; 7207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final int mRowScrollUpAnimationOffset; 7307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 7407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final long mRowAnimationDuration; 7507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final long mOldContentsFadeOutDuration; 7607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final long mCurrentContentsFadeInDuration; 7707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final TimeInterpolator mFastOutSlowIn = new FastOutSlowInInterpolator(); 7807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final TimeInterpolator mFastOutLinearIn = new FastOutLinearInInterpolator(); 7907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final TimeInterpolator mLinearOutSlowIn = new LinearOutSlowInInterpolator(); 8007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private AnimatorSet mAnimatorSet; 8107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ObjectAnimator mTitleFadeOutAnimator; 8207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private final List<ViewPropertyValueHolder> mPropertyValuesAfterAnimation = new ArrayList<>(); 8307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 8407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private TextView mTempTitleViewForOld; 8507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private TextView mTempTitleViewForCurrent; 8607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 8707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public MenuLayoutManager(Context context, MenuView menuView) { 8807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView = menuView; 8907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Load dimensions 9007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Resources res = context.getResources(); 9107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowAlignFromBottom = res.getDimensionPixelOffset(R.dimen.menu_row_align_from_bottom); 9207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowContentsPaddingTop = res.getDimensionPixelOffset(R.dimen.menu_row_contents_padding_top); 9307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowContentsPaddingBottomMax = res.getDimensionPixelOffset( 9407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko R.dimen.menu_row_contents_padding_bottom_max); 9507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowTitleTextDescenderHeight = res.getDimensionPixelOffset( 9607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko R.dimen.menu_row_title_text_descender_height); 9707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuMarginBottomMin = res.getDimensionPixelOffset(R.dimen.menu_margin_bottom_min); 9807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowTitleHeight = res.getDimensionPixelSize(R.dimen.menu_row_title_height); 9907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowScrollUpAnimationOffset = 10007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko res.getDimensionPixelOffset(R.dimen.menu_row_scroll_up_anim_offset); 10107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowAnimationDuration = res.getInteger(R.integer.menu_row_selection_anim_duration); 10207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mOldContentsFadeOutDuration = res.getInteger( 10307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko R.integer.menu_previous_contents_fade_out_duration); 10407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mCurrentContentsFadeInDuration = res.getInteger( 10507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko R.integer.menu_current_contents_fade_in_duration); 10607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 10707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 10807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 10907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Sets the menu rows and views. 11007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 11107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void setMenuRowsAndViews(List<MenuRow> menuRows, List<MenuRowView> menuRowViews) { 11207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRows.clear(); 11307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRows.addAll(menuRows); 11407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.clear(); 11507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.addAll(menuRowViews); 11607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 11707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 11807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 11907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Layouts main menu view. 12007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 12107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * <p>Do not call this method directly. It's supposed to be called only by View.onLayout(). 12207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 12307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void layout(int left, int top, int right, int bottom) { 12407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mAnimatorSet != null) { 12507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Layout will be done after the animation ends. 12607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 12707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 12807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 12907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int count = mMenuRowViews.size(); 13007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView currentView = mMenuRowViews.get(mSelectedPosition); 13107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (currentView.getVisibility() == View.GONE) { 13207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // If the selected row is not visible, select the first visible row. 13307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int firstVisiblePosition = findNextVisiblePosition(-1); 13407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (firstVisiblePosition != -1) { 13507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mSelectedPosition = firstVisiblePosition; 13607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 13707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // No rows are visible. 13807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 13907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 14007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 14107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Rect> layouts = getViewLayouts(left, top, right, bottom); 14207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = 0; i < count; ++i) { 14307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect rect = layouts.get(i); 14407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (rect != null) { 14507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView = mMenuRowViews.get(i); 14607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.layout(rect.left, rect.top, rect.right, rect.bottom); 14707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) dumpChildren("layout()"); 14807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 14907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 15007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 15107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // If the contents view is INVISIBLE initially, it should be changed to GONE after layout. 15207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // See MenuRowView.onFinishInflate() for more information 15307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // TODO: Find a better way to resolve this issue.. 15407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (MenuRowView view : mMenuRowViews) { 15507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (view.getVisibility() == View.VISIBLE 15607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko && view.getContentsView().getVisibility() == View.INVISIBLE) { 15707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko view.onDeselected(); 15807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 15907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 16007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 16107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 16207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private int findNextVisiblePosition(int start) { 16307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int count = mMenuRowViews.size(); 16407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = start + 1; i < count; ++i) { 16507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mMenuRowViews.get(i).getVisibility() != View.GONE) { 16607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return i; 16707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 16807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 16907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return -1; 17007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 17107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 17207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private void dumpChildren(String prefix) { 17307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int position = 0; 17407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (MenuRowView view : mMenuRowViews) { 17507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View title = view.getChildAt(0); 17607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View contents = view.getChildAt(1); 17707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Log.d(TAG, prefix + " position=" + position++ 17807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + " rowView={visiblility=" + view.getVisibility() 17907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", alpha=" + view.getAlpha() 18007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", translationY=" + view.getTranslationY() 18107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", left=" + view.getLeft() + ", top=" + view.getTop() 18207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", right=" + view.getRight() + ", bottom=" + view.getBottom() 18307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + "}, title={visiblility=" + title.getVisibility() 18407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", alpha=" + title.getAlpha() 18507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", translationY=" + title.getTranslationY() 18607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", left=" + title.getLeft() + ", top=" + title.getTop() 18707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", right=" + title.getRight() + ", bottom=" + title.getBottom() 18807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + "}, contents={visiblility=" + contents.getVisibility() 18907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", alpha=" + contents.getAlpha() 19007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", translationY=" + contents.getTranslationY() 19107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", left=" + contents.getLeft() + ", top=" + contents.getTop() 19207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + ", right=" + contents.getRight() + ", bottom=" + contents.getBottom()+ "}"); 19307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 19407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 19507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 19607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 19707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Checks if the view will take up space for the layout not. 19807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 19907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param position The index of the menu row view in the list. This is not the index of the view 20007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * in the screen. 20107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param view The menu row view. 20207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param rowsToAdd The menu row views to be added in the next layout process. 20307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param rowsToRemove The menu row views to be removed in the next layout process. 20407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @return {@code true} if the view will take up space for the layout, otherwise {@code false}. 20507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 20607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private boolean isVisibleInLayout(int position, MenuRowView view, List<Integer> rowsToAdd, 20707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Integer> rowsToRemove) { 20807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Checks if the view will be visible or not. 20907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return (view.getVisibility() != View.GONE && !rowsToRemove.contains(position)) 21007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko || rowsToAdd.contains(position); 21107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 21207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 21307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 21407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Calculates and returns a list of the layout bounds of the menu row views for the layout. 21507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 21607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param left The left coordinate of the menu view. 21707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param top The top coordinate of the menu view. 21807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param right The right coordinate of the menu view. 21907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param bottom The bottom coordinate of the menu view. 22007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 22107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private List<Rect> getViewLayouts(int left, int top, int right, int bottom) { 22207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return getViewLayouts(left, top, right, bottom, Collections.<Integer>emptyList(), 22307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Collections.<Integer>emptyList()); 22407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 22507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 22607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 22707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Calculates and returns a list of the layout bounds of the menu row views for the layout. The 22807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * order of the bounds is the same as that of the menu row views. e.g. the second rectangle in 22907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * the list is for the second menu row view in the view list (not the second view in the 23007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * screen). 23107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 23207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * <p>It predicts the layout bounds for the next layout process. Some views will be added or 23307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * removed in the layout, so they need to be considered here. 23407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 23507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param left The left coordinate of the menu view. 23607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param top The top coordinate of the menu view. 23707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param right The right coordinate of the menu view. 23807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param bottom The bottom coordinate of the menu view. 23907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param rowsToAdd The menu row views to be added in the next layout process. 24007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @param rowsToRemove The menu row views to be removed in the next layout process. 24107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * @return the layout bounds of the menu row views. 24207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 24307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private List<Rect> getViewLayouts(int left, int top, int right, int bottom, 24407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Integer> rowsToAdd, List<Integer> rowsToRemove) { 24507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The coordinates should be relative to the parent. 24607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int relativeLeft = 0; 24707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int relateiveRight = right - left; 24807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int relativeBottom = bottom - top; 24907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 25007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Rect> layouts = new ArrayList<>(); 25107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int count = mMenuRowViews.size(); 25207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView selectedView = mMenuRowViews.get(mSelectedPosition); 25307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int rowTitleHeight = selectedView.getTitleView().getMeasuredHeight(); 25407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int rowContentsHeight = selectedView.getPreferredContentsHeight(); 25507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Calculate for the selected row first. 25607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The distance between the bottom of the screen and the vertical center of the contents 25707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // should be kept fixed. For more information, please see the redlines. 25807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int childTop = relativeBottom - mRowAlignFromBottom - rowContentsHeight / 2 25907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko - mRowContentsPaddingTop - rowTitleHeight; 26007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int childBottom = relativeBottom; 26107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int position = mSelectedPosition + 1; 26207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (; position < count; ++position) { 26307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Find and layout the next row to calculate the bottom line of the selected row. 26407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView nextView = mMenuRowViews.get(position); 26507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (isVisibleInLayout(position, nextView, rowsToAdd, rowsToRemove)) { 26607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int nextTitleTopMax = relativeBottom - mMenuMarginBottomMin - rowTitleHeight 26707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + mRowTitleTextDescenderHeight; 26807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int childBottomMax = relativeBottom - mRowAlignFromBottom + rowContentsHeight / 2 26907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + mRowContentsPaddingBottomMax - rowTitleHeight; 27007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko childBottom = Math.min(nextTitleTopMax, childBottomMax); 27107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(new Rect(relativeLeft, childBottom, relateiveRight, relativeBottom)); 27207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko break; 27307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 27407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // null means that the row is GONE. 27507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(null); 27607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 27707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 27807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(0, new Rect(relativeLeft, childTop, relateiveRight, childBottom)); 27907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Layout the previous rows. 28007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = mSelectedPosition - 1; i >= 0; --i) { 28107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(i); 28207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (isVisibleInLayout(i, view, rowsToAdd, rowsToRemove)) { 28307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko childTop -= mRowTitleHeight; 28407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko childBottom = childTop + rowTitleHeight; 28507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(0, new Rect(relativeLeft, childTop, relateiveRight, childBottom)); 28607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 28707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(0, null); 28807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 28907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 29007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Move all the next rows to the below of the screen. 29107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko childTop = relativeBottom; 29207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (++position; position < count; ++position) { 29307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(position); 29407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (isVisibleInLayout(position, view, rowsToAdd, rowsToRemove)) { 29507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko childBottom = childTop + rowTitleHeight; 29607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(new Rect(relativeLeft, childTop, relateiveRight, childBottom)); 29707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko childTop += mRowTitleHeight; 29807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 29907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layouts.add(null); 30007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 30107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 30207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return layouts; 30307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 30407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 30507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 30607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Move the current selection to the given {@code position}. 30707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 30807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void setSelectedPosition(int position) { 30907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) { 31007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Log.d(TAG, "setSelectedPosition(position=" + position + ") {previousPosition=" 31107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + mSelectedPosition + "}"); 31207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 31307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mSelectedPosition == position) { 31407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 31507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 3167d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko boolean indexValid = Utils.isIndexValid(mMenuRowViews, position); 3177d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko SoftPreconditions.checkArgument(indexValid, TAG, "position " + position); 3187d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (!indexValid) { 31907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 32007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 32148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho MenuRow row = mMenuRows.get(position); 32248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (!row.isVisible()) { 32348dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.e(TAG, "Selecting invisible row: " + position); 32448dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return; 32548dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 3267d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (Utils.isIndexValid(mMenuRowViews, mSelectedPosition)) { 32707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.get(mSelectedPosition).onDeselected(); 32807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 32907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mSelectedPosition = position; 3307d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (Utils.isIndexValid(mMenuRowViews, mSelectedPosition)) { 33107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.get(mSelectedPosition).onSelected(false); 33207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 33307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mMenuView.getVisibility() == View.VISIBLE) { 33407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Request focus after the new contents view shows up. 33507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.requestFocus(); 33607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Adjust the position of the selected row. 33707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.requestLayout(); 33807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 33907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 34007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 34107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 34207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Move the current selection to the given {@code position} with animation. 34307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * The animation specification is included in http://b/21069476 34407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 34507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void setSelectedPositionSmooth(final int position) { 34607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) { 34707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Log.d(TAG, "setSelectedPositionSmooth(position=" + position + ") {previousPosition=" 34807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko + mSelectedPosition + "}"); 34907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 35007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mMenuView.getVisibility() != View.VISIBLE) { 35107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko setSelectedPosition(position); 35207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 35307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 35407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mSelectedPosition == position) { 35507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 35607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 3577d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko boolean oldIndexValid = Utils.isIndexValid(mMenuRowViews, mSelectedPosition); 3587d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko SoftPreconditions 3597d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko .checkState(oldIndexValid, TAG, "No previous selection: " + mSelectedPosition); 3607d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (!oldIndexValid) { 36107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 36207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 3637d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko boolean newIndexValid = Utils.isIndexValid(mMenuRowViews, position); 3647d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko SoftPreconditions.checkArgument(newIndexValid, TAG, "position " + position); 3657d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko if (!newIndexValid) { 36607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 36707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 36848dadb49248271b01997862e1335912a4f2e189fYoungsang Cho MenuRow row = mMenuRows.get(position); 36948dadb49248271b01997862e1335912a4f2e189fYoungsang Cho if (!row.isVisible()) { 37048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho Log.e(TAG, "Moving to the invisible row: " + position); 37148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho return; 37248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho } 37307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mAnimatorSet != null) { 37407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Do not cancel the animation here. The property values should be set to the end values 37507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // when the animation finishes. 37607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.end(); 37707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 37807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mTitleFadeOutAnimator != null) { 37907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Cancel the animation instead of ending it in order that the title animation starts 38007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // again from the intermediate state. 38107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator.cancel(); 38207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 38307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko final int oldPosition = mSelectedPosition; 38407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mSelectedPosition = position; 38507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) dumpChildren("startRowAnimation()"); 38607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 38707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView currentView = mMenuRowViews.get(position); 38807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Show the children of the next row. 38907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleView().setVisibility(View.VISIBLE); 39007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getContentsView().setVisibility(View.VISIBLE); 39107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Request focus after the new contents view shows up. 39207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.requestFocus(); 39307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mTempTitleViewForOld == null) { 39407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Initialize here because we don't know when the views are inflated. 39507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForOld = 39607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko (TextView) mMenuView.findViewById(R.id.temp_title_for_old); 39707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForCurrent = 39807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko (TextView) mMenuView.findViewById(R.id.temp_title_for_current); 39907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 40007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 40107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Animations. 40207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mPropertyValuesAfterAnimation.clear(); 40307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Animator> animators = new ArrayList<>(); 40407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko boolean scrollDown = position > oldPosition; 40507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Rect> layouts = getViewLayouts(mMenuView.getLeft(), mMenuView.getTop(), 40607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.getRight(), mMenuView.getBottom()); 40707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 40807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Old row. 40907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRow oldRow = mMenuRows.get(oldPosition); 41007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView oldView = mMenuRowViews.get(oldPosition); 41107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View oldContentsView = oldView.getContentsView(); 41207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Old contents view. 41307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(oldContentsView, 1.0f, 0.0f, 1.0f, mLinearOutSlowIn) 41407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko .setDuration(mOldContentsFadeOutDuration)); 41507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko final TextView oldTitleView = oldView.getTitleView(); 41607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko setTempTitleView(mTempTitleViewForOld, oldTitleView); 41707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect oldLayoutRect = layouts.get(oldPosition); 41807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (scrollDown) { 41907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Old title view. 42007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (oldRow.hideTitleWhenSelected() && oldTitleView.getVisibility() != View.VISIBLE) { 42107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // This case is not included in the animation specification. 42207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForOld.setScaleX(1.0f); 42307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForOld.setScaleY(1.0f); 42407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(mTempTitleViewForOld, 0.0f, 42507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewAlphaDeselected(), mFastOutLinearIn)); 42607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int offset = oldLayoutRect.top - mTempTitleViewForOld.getTop(); 42707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(mTempTitleViewForOld, 42807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko offset + mRowScrollUpAnimationOffset, offset)); 42907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 43007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleXAnimator(mTempTitleViewForOld, 43107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewScaleSelected(), 1.0f)); 43207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleYAnimator(mTempTitleViewForOld, 43307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewScaleSelected(), 1.0f)); 43407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(mTempTitleViewForOld, oldTitleView.getAlpha(), 43507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewAlphaDeselected(), mLinearOutSlowIn)); 43607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(mTempTitleViewForOld, 0, 43707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldLayoutRect.top - mTempTitleViewForOld.getTop())); 43807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 43907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldTitleView.setAlpha(oldView.getTitleViewAlphaDeselected()); 44007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldTitleView.setVisibility(View.INVISIBLE); 44107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 44207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect currentLayoutRect = new Rect(layouts.get(position)); 44307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Old title view. 44407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The move distance in the specification is 32dp(mRowScrollUpAnimationOffset). 44507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // But if the height of the upper row is small, the upper row will move down a lot. In 44607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // this case, this row needs to move more than the specification to avoid the overlap of 44707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // the two titles. 44807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The maximum is to the top of the start position of mTempTitleViewForOld. 44907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int distanceCurrentTitle = currentLayoutRect.top - currentView.getTop(); 45007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int distance = Math.max(mRowScrollUpAnimationOffset, distanceCurrentTitle); 45107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int distanceToTopOfSecondTitle = oldLayoutRect.top - mRowScrollUpAnimationOffset 45207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko - oldView.getTop(); 45307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(oldTitleView, 0.0f, 45407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Math.min(distance, distanceToTopOfSecondTitle))); 45507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(oldTitleView, 1.0f, 0.0f, 1.0f, mLinearOutSlowIn) 45607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko .setDuration(mOldContentsFadeOutDuration)); 45707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleXAnimator(oldTitleView, 45807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewScaleSelected(), 1.0f)); 45907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleYAnimator(oldTitleView, 46007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewScaleSelected(), 1.0f)); 46107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForOld.setScaleX(1.0f); 46207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForOld.setScaleY(1.0f); 46307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(mTempTitleViewForOld, 0.0f, 46407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldView.getTitleViewAlphaDeselected(), mFastOutLinearIn)); 46507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int offset = oldLayoutRect.top - mTempTitleViewForOld.getTop(); 46607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(mTempTitleViewForOld, 46707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko offset - mRowScrollUpAnimationOffset, offset)); 46807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 46907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Current row. 47007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect currentLayoutRect = new Rect(layouts.get(position)); 47107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko TextView currentTitleView = currentView.getTitleView(); 47207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View currentContentsView = currentView.getContentsView(); 47307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentContentsView.setAlpha(0.0f); 47407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (scrollDown) { 47507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Current title view. 47607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko setTempTitleView(mTempTitleViewForCurrent, currentTitleView); 47707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The move distance in the specification is 32dp(mRowScrollUpAnimationOffset). 47807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // But if the height of the upper row is small, the upper row will move up a lot. In 47907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // this case, this row needs to start the move from more than the specification to avoid 48007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // the overlap of the two titles. 48107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The maximum is to the top of the end position of mTempTitleViewForCurrent. 48207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int distanceOldTitle = oldView.getTop() - oldLayoutRect.top; 48307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int distance = Math.max(mRowScrollUpAnimationOffset, distanceOldTitle); 48407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int distanceTopOfSecondTitle = currentView.getTop() - mRowScrollUpAnimationOffset 48507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko - currentLayoutRect.top; 48607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(currentTitleView, 48707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Math.min(distance, distanceTopOfSecondTitle), 0.0f)); 48807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.setTop(currentLayoutRect.top); 48907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = createAlphaAnimator(currentTitleView, 0.0f, 1.0f, 49007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mFastOutLinearIn).setDuration(mCurrentContentsFadeInDuration); 49107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setStartDelay(mOldContentsFadeOutDuration); 49207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentTitleView.setAlpha(0.0f); 49307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(animator); 49407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleXAnimator(currentTitleView, 1.0f, 49507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleViewScaleSelected())); 49607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleYAnimator(currentTitleView, 1.0f, 49707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleViewScaleSelected())); 49807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(mTempTitleViewForCurrent, 0.0f, 49907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko -mRowScrollUpAnimationOffset)); 50007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(mTempTitleViewForCurrent, 50107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleViewAlphaDeselected(), 0, mLinearOutSlowIn)); 50207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Current contents view. 50307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(currentContentsView, 50407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRowScrollUpAnimationOffset, 0.0f)); 50507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator = createAlphaAnimator(currentContentsView, 0.0f, 1.0f, mFastOutLinearIn) 50607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko .setDuration(mCurrentContentsFadeInDuration); 50707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setStartDelay(mOldContentsFadeOutDuration); 50807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(animator); 50907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 51007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.setBottom(currentLayoutRect.bottom); 51107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Current title view. 51207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int currentViewOffset = currentLayoutRect.top - currentView.getTop(); 51307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(currentTitleView, 0, currentViewOffset)); 51407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(currentTitleView, 51507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleViewAlphaDeselected(), 1.0f, mFastOutSlowIn)); 51607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleXAnimator(currentTitleView, 1.0f, 51707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleViewScaleSelected())); 51807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createScaleYAnimator(currentTitleView, 1.0f, 51907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentView.getTitleViewScaleSelected())); 52007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Current contents view. 52107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(currentContentsView, 52207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko currentViewOffset - mRowScrollUpAnimationOffset, currentViewOffset)); 52307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = createAlphaAnimator(currentContentsView, 0.0f, 1.0f, 52407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mFastOutLinearIn).setDuration(mCurrentContentsFadeInDuration); 52507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setStartDelay(mOldContentsFadeOutDuration); 52607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(animator); 52707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 52807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Next row. 52907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int nextPosition; 53007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (scrollDown) { 53107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko nextPosition = findNextVisiblePosition(position); 53207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (nextPosition != -1) { 53307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView nextView = mMenuRowViews.get(nextPosition); 53407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect nextLayoutRect = layouts.get(nextPosition); 53507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(nextView, 53607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko nextLayoutRect.top + mRowScrollUpAnimationOffset - nextView.getTop(), 53707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko nextLayoutRect.top - nextView.getTop())); 53807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(nextView, 0.0f, 1.0f, mFastOutLinearIn)); 53907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 54007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 54107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko nextPosition = findNextVisiblePosition(oldPosition); 54207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (nextPosition != -1) { 54307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView nextView = mMenuRowViews.get(nextPosition); 54407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(nextView, 0, mRowScrollUpAnimationOffset)); 54507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(nextView, 54607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko nextView.getTitleViewAlphaDeselected(), 0.0f, 1.0f, mLinearOutSlowIn)); 54707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 54807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 54907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Other rows. 55007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int count = mMenuRowViews.size(); 55107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = 0; i < count; ++i) { 55207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(i); 55307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (view.getVisibility() == View.VISIBLE && i != oldPosition && i != position 55407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko && i != nextPosition) { 55507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect rect = layouts.get(i); 55607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(view, 0, rect.top - view.getTop())); 55707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 55807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 55907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Run animation. 56007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko final List<ViewPropertyValueHolder> propertyValuesAfterAnimation = new ArrayList<>(); 56107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko propertyValuesAfterAnimation.addAll(mPropertyValuesAfterAnimation); 56207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet = new AnimatorSet(); 56307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.playTogether(animators); 56407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.addListener(new AnimatorListenerAdapter() { 56507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko @Override 56607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onAnimationEnd(Animator animator) { 56707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) dumpChildren("onRowAnimationEndBefore"); 56807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet = null; 56907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The property values which are different from the end values and need to be 57007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // changed after the animation are set here. 57107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // e.g. setting translationY to 0, alpha of the contents view to 1. 57207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (ViewPropertyValueHolder holder : propertyValuesAfterAnimation) { 57307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko holder.property.set(holder.view, holder.value); 57407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 57507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko oldTitleView.setVisibility(View.VISIBLE); 57607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.get(oldPosition).onDeselected(); 57707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.get(position).onSelected(true); 57807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForOld.setVisibility(View.GONE); 57907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTempTitleViewForCurrent.setVisibility(View.GONE); 58007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layout(mMenuView.getLeft(), mMenuView.getTop(), mMenuView.getRight(), 58107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.getBottom()); 58207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) dumpChildren("onRowAnimationEndAfter"); 58307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 58407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRow currentRow = mMenuRows.get(position); 58507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (currentRow.hideTitleWhenSelected()) { 58607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View titleView = mMenuRowViews.get(position).getTitleView(); 58707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator = createAlphaAnimator(titleView, titleView.getAlpha(), 58807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 0.0f, mLinearOutSlowIn); 58907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator.setStartDelay(TITLE_SHOW_DURATION_BEFORE_HIDDEN_MS); 59007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator.addListener(new AnimatorListenerAdapter() { 59107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private boolean mCanceled; 59207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 59307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko @Override 59407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onAnimationCancel(Animator animator) { 59507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mCanceled = true; 59607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 59707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 59807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko @Override 59907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onAnimationEnd(Animator animator) { 60007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator = null; 60107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (!mCanceled) { 60207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.get(position).onSelected(false); 60307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 60407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 60507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko }); 60607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator.start(); 60707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 60807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 60907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko }); 61007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.start(); 61107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) dumpChildren("startedRowAnimation()"); 61207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 61307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 61407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private void setTempTitleView(TextView dest, TextView src) { 61507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setVisibility(View.VISIBLE); 61607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setText(src.getText()); 61707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setTranslationY(0.0f); 61807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (src.getVisibility() == View.VISIBLE) { 61907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setAlpha(src.getAlpha()); 62007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setScaleX(src.getScaleX()); 62107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setScaleY(src.getScaleY()); 62207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else { 62307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setAlpha(0.0f); 62407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setScaleX(1.0f); 62507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setScaleY(1.0f); 62607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 62707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View parent = (View) src.getParent(); 62807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setLeft(src.getLeft() + parent.getLeft()); 62907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setRight(src.getRight() + parent.getLeft()); 63007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setTop(src.getTop() + parent.getTop()); 63107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko dest.setBottom(src.getBottom() + parent.getTop()); 63207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 63307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 63407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 63507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Called when the menu row information is updated. The add/remove animation of the row views 63607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * will be started. 63707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * 63807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * <p>Note that the current row should not be removed. 63907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 64007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onMenuRowUpdated() { 64107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mMenuView.getVisibility() != View.VISIBLE) { 64207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int count = mMenuRowViews.size(); 64307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = 0; i < count; ++i) { 6447d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko mMenuRowViews.get(i) 6457d67089aa1e9aa2123c3cd2f386d7019a1544db1Nick Chalko .setVisibility(mMenuRows.get(i).isVisible() ? View.VISIBLE : View.GONE); 64607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 64707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 64807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 64907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 65007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Integer> addedRowViews = new ArrayList<>(); 65107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Integer> removedRowViews = new ArrayList<>(); 65207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Map<Integer, Integer> offsetsToMove = new HashMap<>(); 65307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int added = 0; 65407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = mSelectedPosition - 1; i >= 0; --i) { 65507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRow row = mMenuRows.get(i); 65607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(i); 65707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (row.isVisible() && (view.getVisibility() == View.GONE 65807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko || mRemovingRowViews.contains(i))) { 65907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Removing rows are still VISIBLE. 66007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko addedRowViews.add(i); 66107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ++added; 66207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else if (!row.isVisible() && view.getVisibility() == View.VISIBLE) { 66307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko removedRowViews.add(i); 66407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko --added; 66507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else if (added != 0) { 66607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko offsetsToMove.put(i, -added); 66707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 66807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 66907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko added = 0; 67007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko int count = mMenuRowViews.size(); 67107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int i = mSelectedPosition + 1; i < count; ++i) { 67207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRow row = mMenuRows.get(i); 67307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(i); 67407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (row.isVisible() && (view.getVisibility() == View.GONE 67507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko || mRemovingRowViews.contains(i))) { 67607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Removing rows are still VISIBLE. 67707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko addedRowViews.add(i); 67807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ++added; 67907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else if (!row.isVisible() && view.getVisibility() == View.VISIBLE) { 68007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko removedRowViews.add(i); 68107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko --added; 68207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } else if (added != 0) { 68307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko offsetsToMove.put(i, added); 68407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 68507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 68607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (addedRowViews.size() == 0 && removedRowViews.size() == 0) { 68707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return; 68807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 68907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 69007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mAnimatorSet != null) { 69107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Do not cancel the animation here. The property values should be set to the end values 69207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // when the animation finishes. 69307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.end(); 69407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 69507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mTitleFadeOutAnimator != null) { 69607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator.end(); 69707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 69807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mPropertyValuesAfterAnimation.clear(); 69907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Animator> animators = new ArrayList<>(); 70007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko List<Rect> layouts = getViewLayouts(mMenuView.getLeft(), mMenuView.getTop(), 70107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.getRight(), mMenuView.getBottom(), addedRowViews, removedRowViews); 70207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int position : addedRowViews) { 70307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(position); 70407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko view.setVisibility(View.VISIBLE); 70507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko Rect rect = layouts.get(position); 70607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // TODO: The animation is not visible when it is shown for the first time. Need to find 70707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // a better way to resolve this issue. 70807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko view.layout(rect.left, rect.top, rect.right, rect.bottom); 70907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko View titleView = view.getTitleView(); 71007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MarginLayoutParams params = (MarginLayoutParams) titleView.getLayoutParams(); 71107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko titleView.layout(view.getPaddingLeft() + params.leftMargin, 71207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko view.getPaddingTop() + params.topMargin, 71307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko rect.right - rect.left - view.getPaddingRight() - params.rightMargin, 71407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko rect.bottom - rect.top - view.getPaddingBottom() - params.bottomMargin); 71507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(view, 0.0f, 1.0f, mFastOutLinearIn)); 71607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 71707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int position : removedRowViews) { 71807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(position); 71907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createAlphaAnimator(view, 1.0f, 0.0f, 1.0f, mLinearOutSlowIn)); 72007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 72107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (Entry<Integer, Integer> entry : offsetsToMove.entrySet()) { 72207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko MenuRowView view = mMenuRowViews.get(entry.getKey()); 72307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animators.add(createTranslationYAnimator(view, 0, entry.getValue() * mRowTitleHeight)); 72407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 72507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Run animation. 72607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko final List<ViewPropertyValueHolder> propertyValuesAfterAnimation = new ArrayList<>(); 72707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko propertyValuesAfterAnimation.addAll(mPropertyValuesAfterAnimation); 72807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRemovingRowViews.clear(); 72907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mRemovingRowViews.addAll(removedRowViews); 73007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet = new AnimatorSet(); 73107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.playTogether(animators); 73207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.addListener(new AnimatorListenerAdapter() { 73307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko @Override 73407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onAnimationEnd(Animator animation) { 73507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet = null; 73607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // The property values which are different from the end values and need to be 73707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // changed after the animation are set here. 73807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // e.g. setting translationY to 0, alpha of the contents view to 1. 73907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (ViewPropertyValueHolder holder : propertyValuesAfterAnimation) { 74007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko holder.property.set(holder.view, holder.value); 74107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 74207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko for (int position : mRemovingRowViews) { 74307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuRowViews.get(position).setVisibility(View.GONE); 74407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 74507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko layout(mMenuView.getLeft(), mMenuView.getTop(), mMenuView.getRight(), 74607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mMenuView.getBottom()); 74707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 74807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko }); 74907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.start(); 75007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (DEBUG) dumpChildren("onMenuRowUpdated()"); 75107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 75207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 75307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ObjectAnimator createTranslationYAnimator(View view, float from, float to) { 75407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, from, to); 75507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setDuration(mRowAnimationDuration); 75607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setInterpolator(mFastOutSlowIn); 75707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mPropertyValuesAfterAnimation.add(new ViewPropertyValueHolder(View.TRANSLATION_Y, view, 0)); 75807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return animator; 75907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 76007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 76107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ObjectAnimator createAlphaAnimator(View view, float from, float to, 76207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko TimeInterpolator interpolator) { 76307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, from, to); 76407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setDuration(mRowAnimationDuration); 76507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setInterpolator(interpolator); 76607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return animator; 76707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 76807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 76907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ObjectAnimator createAlphaAnimator(View view, float from, float to, float end, 77007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko TimeInterpolator interpolator) { 77107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA, from, to); 77207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setDuration(mRowAnimationDuration); 77307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setInterpolator(interpolator); 77407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mPropertyValuesAfterAnimation.add(new ViewPropertyValueHolder(View.ALPHA, view, end)); 77507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return animator; 77607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 77707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 77807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ObjectAnimator createScaleXAnimator(View view, float from, float to) { 77907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.SCALE_X, from, to); 78007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setDuration(mRowAnimationDuration); 78107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setInterpolator(mFastOutSlowIn); 78207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return animator; 78307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 78407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 78507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private ObjectAnimator createScaleYAnimator(View view, float from, float to) { 78607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.SCALE_Y, from, to); 78707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setDuration(mRowAnimationDuration); 78807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko animator.setInterpolator(mFastOutSlowIn); 78907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return animator; 79007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 79107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 79207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 79307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Returns the current position. 79407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 79507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public int getSelectedPosition() { 79607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko return mSelectedPosition; 79707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 79807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 79907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko private static final class ViewPropertyValueHolder { 80048dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public final Property<View, Float> property; 80148dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public final View view; 80248dadb49248271b01997862e1335912a4f2e189fYoungsang Cho public final float value; 80307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 80407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public ViewPropertyValueHolder(Property<View, Float> property, View view, float value) { 80507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko this.property = property; 80607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko this.view = view; 80707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko this.value = value; 80807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 80907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 81007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 81107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 81207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Called when the menu becomes visible. 81307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 81407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onMenuShow() { 81507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 81607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko 81707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko /** 81807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko * Called when the menu becomes hidden. 81907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko */ 82007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko public void onMenuHide() { 82107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mAnimatorSet != null) { 82207b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet.end(); 82307b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mAnimatorSet = null; 82407b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 82507b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko // Should be finished after the animator set. 82607b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko if (mTitleFadeOutAnimator != null) { 82707b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator.end(); 82807b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko mTitleFadeOutAnimator = null; 82907b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 83007b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko } 83107b043dc3db83d6d20f0e8513b946830ab00e37bNick Chalko} 832