Loading core/java/android/widget/ActionMenuPresenter.java +247 −13 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package android.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; Loading @@ -24,6 +28,7 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.ActionProvider; import android.view.Gravity; Loading @@ -32,6 +37,7 @@ import android.view.SoundEffectConstants; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ListPopupWindow.ForwardingListener; import com.android.internal.transition.ActionBarTransition; Loading @@ -45,6 +51,7 @@ import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; import java.util.ArrayList; import java.util.List; /** * MenuPresenter for building action menus as seen in the action bar and action modes. Loading @@ -54,6 +61,7 @@ import java.util.ArrayList; public class ActionMenuPresenter extends BaseMenuPresenter implements ActionProvider.SubUiVisibilityListener { private static final String TAG = "ActionMenuPresenter"; private static final int ITEM_ANIMATION_DURATION = 150; private OverflowMenuButton mOverflowButton; private boolean mReserveOverflow; Loading @@ -71,8 +79,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter // Group IDs that have been added as actions - used temporarily, allocated here for reuse. private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray(); private View mScrapActionButtonView; private OverflowPopup mOverflowPopup; private ActionButtonSubmenu mActionButtonPopup; Loading @@ -84,6 +90,18 @@ public class ActionMenuPresenter extends BaseMenuPresenter final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback(); int mOpenSubMenuId; // These collections are used to store pre- and post-layout information for menu items, // which is used to determine appropriate animations to run for changed items. private SparseArray<MenuItemLayoutInfo> mPreLayoutItems = new SparseArray<MenuItemLayoutInfo>(); private SparseArray<MenuItemLayoutInfo> mPostLayoutItems = new SparseArray<MenuItemLayoutInfo>(); // The list of currently running animations on menu items. private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>(); public ActionMenuPresenter(Context context) { super(context, com.android.internal.R.layout.action_menu_layout, com.android.internal.R.layout.action_menu_item_layout); Loading Loading @@ -125,9 +143,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter mActionItemWidthLimit = width; mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density); // Drop a scrap view as it may no longer reflect the proper context/config. mScrapActionButtonView = null; } public void onConfigurationChanged(Configuration newConfig) { Loading Loading @@ -202,10 +217,186 @@ public class ActionMenuPresenter extends BaseMenuPresenter return item.isActionButton(); } /** * Store layout information about current items in the menu. This is stored for * both pre- and post-layout phases and compared in runItemAnimations() to determine * the animations that need to be run on any item changes. * * @param preLayout Whether this is being called in the pre-layout phase. This is passed * into the MenuItemLayoutInfo structure to store the appropriate position values. */ private void computeMenuItemAnimationInfo(boolean preLayout) { final ViewGroup menuViewParent = (ViewGroup) mMenuView; final int count = menuViewParent.getChildCount(); SparseArray items = preLayout ? mPreLayoutItems : mPostLayoutItems; for (int i = 0; i < count; ++i) { View child = menuViewParent.getChildAt(i); final int id = child.getId(); if (id > 0 && child.getWidth() != 0 && child.getHeight() != 0) { MenuItemLayoutInfo info = new MenuItemLayoutInfo(child, preLayout); items.put(id, info); } } } /** * This method is called once both the pre-layout and post-layout steps have * happened. It figures out which views are new (didn't exist prior to layout), * gone (existed pre-layout, but are now gone), or changed (exist in both, * but in a different location) and runs appropriate animations on those views. * Items are tracked by ids, since the underlying views that represent items * pre- and post-layout may be different. */ private void runItemAnimations() { for (int i = 0; i < mPreLayoutItems.size(); ++i) { int id = mPreLayoutItems.keyAt(i); final MenuItemLayoutInfo menuItemLayoutInfoPre = mPreLayoutItems.get(id); final int postLayoutIndex = mPostLayoutItems.indexOfKey(id); if (postLayoutIndex >= 0) { // item exists pre and post: see if it's changed final MenuItemLayoutInfo menuItemLayoutInfoPost = mPostLayoutItems.valueAt(postLayoutIndex); PropertyValuesHolder pvhX = null; PropertyValuesHolder pvhY = null; if (menuItemLayoutInfoPre.left != menuItemLayoutInfoPost.left) { pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, (menuItemLayoutInfoPre.left - menuItemLayoutInfoPost.left), 0); } if (menuItemLayoutInfoPre.top != menuItemLayoutInfoPost.top) { pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, menuItemLayoutInfoPre.top - menuItemLayoutInfoPost.top, 0); } if (pvhX != null || pvhY != null) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j); if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.MOVE) { oldInfo.animator.cancel(); } } ObjectAnimator anim; if (pvhX != null) { if (pvhY != null) { anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhX, pvhY); } else { anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhX); } } else { anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhY); } anim.setDuration(ITEM_ANIMATION_DURATION); anim.start(); ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfoPost, anim, ItemAnimationInfo.MOVE); mRunningItemAnimations.add(info); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { if (mRunningItemAnimations.get(j).animator == animation) { mRunningItemAnimations.remove(j); break; } } } }); } mPostLayoutItems.remove(id); } else { // item used to be there, is now gone float oldAlpha = 1; for (int j = 0; j < mRunningItemAnimations.size(); ++j) { ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j); if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.FADE_IN) { oldAlpha = oldInfo.menuItemLayoutInfo.view.getAlpha(); oldInfo.animator.cancel(); } } ObjectAnimator anim = ObjectAnimator.ofFloat(menuItemLayoutInfoPre.view, View.ALPHA, oldAlpha, 0); // Re-using the view from pre-layout assumes no view recycling ((ViewGroup) mMenuView).getOverlay().add(menuItemLayoutInfoPre.view); anim.setDuration(ITEM_ANIMATION_DURATION); anim.start(); ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfoPre, anim, ItemAnimationInfo.FADE_OUT); mRunningItemAnimations.add(info); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { if (mRunningItemAnimations.get(j).animator == animation) { mRunningItemAnimations.remove(j); break; } } ((ViewGroup) mMenuView).getOverlay().remove(menuItemLayoutInfoPre.view); } }); } } for (int i = 0; i < mPostLayoutItems.size(); ++i) { int id = mPostLayoutItems.keyAt(i); final int postLayoutIndex = mPostLayoutItems.indexOfKey(id); if (postLayoutIndex >= 0) { // item is new final MenuItemLayoutInfo menuItemLayoutInfo = mPostLayoutItems.valueAt(postLayoutIndex); float oldAlpha = 0; for (int j = 0; j < mRunningItemAnimations.size(); ++j) { ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j); if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.FADE_OUT) { oldAlpha = oldInfo.menuItemLayoutInfo.view.getAlpha(); oldInfo.animator.cancel(); } } ObjectAnimator anim = ObjectAnimator.ofFloat(menuItemLayoutInfo.view, View.ALPHA, oldAlpha, 1); anim.start(); anim.setDuration(ITEM_ANIMATION_DURATION); ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfo, anim, ItemAnimationInfo.FADE_IN); mRunningItemAnimations.add(info); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { if (mRunningItemAnimations.get(j).animator == animation) { mRunningItemAnimations.remove(j); break; } } } }); } } mPreLayoutItems.clear(); mPostLayoutItems.clear(); } /** * Gets position/existence information on menu items before and after layout, * which is then fed into runItemAnimations() */ private void setupItemAnimations() { final ViewGroup menuViewParent = (ViewGroup) mMenuView; computeMenuItemAnimationInfo(true); final ViewTreeObserver observer = menuViewParent.getViewTreeObserver(); if (observer != null) { observer.addOnDrawListener(new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { computeMenuItemAnimationInfo(false); observer.removeOnDrawListener(this); runItemAnimations(); } }); } } @Override public void updateMenuView(boolean cleared) { final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent(); if (menuViewParent != null) { setupItemAnimations(); ActionBarTransition.beginDelayedTransition(menuViewParent); } super.updateMenuView(cleared); Loading Loading @@ -431,10 +622,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter MenuItemImpl item = visibleItems.get(i); if (item.requiresActionButton()) { View v = getItemView(item, mScrapActionButtonView, parent); if (mScrapActionButtonView == null) { mScrapActionButtonView = v; } View v = getItemView(item, null, parent); if (mStrictWidthLimit) { cellsRemaining -= ActionMenuView.measureChildForCells(v, cellSize, cellsRemaining, querySpec, 0); Loading @@ -460,10 +648,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter (!mStrictWidthLimit || cellsRemaining > 0); if (isAction) { View v = getItemView(item, mScrapActionButtonView, parent); if (mScrapActionButtonView == null) { mScrapActionButtonView = v; } View v = getItemView(item, null, parent); if (mStrictWidthLimit) { final int cells = ActionMenuView.measureChildForCells(v, cellSize, cellsRemaining, querySpec, 0); Loading Loading @@ -819,4 +1004,53 @@ public class ActionMenuPresenter extends BaseMenuPresenter boolean mHasTintMode; boolean mHasTintList; } /** * This class holds layout information for a menu item. This is used to determine * pre- and post-layout information about menu items, which will then be used to * determine appropriate item animations. */ private static class MenuItemLayoutInfo { View view; int left; int top; MenuItemLayoutInfo(View view, boolean preLayout) { left = view.getLeft(); top = view.getTop(); if (preLayout) { // We track translation for pre-layout because a view might be mid-animation // and we need this information to know where to animate from left += view.getTranslationX(); top += view.getTranslationY(); } this.view = view; } } /** * This class is used to store information about currently-running item animations. * This is used when new animations are scheduled to determine whether any existing * animations need to be canceled, based on whether the running animations overlap * with any new animations. For example, if an item is currently animating from * location A to B and another change dictates that it be animated to C, then the current * A-B animation will be canceled and a new animation to C will be started. */ private static class ItemAnimationInfo { int id; MenuItemLayoutInfo menuItemLayoutInfo; Animator animator; int animType; static final int MOVE = 0; static final int FADE_IN = 1; static final int FADE_OUT = 2; ItemAnimationInfo(int id, MenuItemLayoutInfo info, Animator anim, int animType) { this.id = id; menuItemLayoutInfo = info; animator = anim; this.animType = animType; } } } Loading
core/java/android/widget/ActionMenuPresenter.java +247 −13 Original line number Diff line number Diff line Loading @@ -16,6 +16,10 @@ package android.widget; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; Loading @@ -24,6 +28,7 @@ import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.ActionProvider; import android.view.Gravity; Loading @@ -32,6 +37,7 @@ import android.view.SoundEffectConstants; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.ListPopupWindow.ForwardingListener; import com.android.internal.transition.ActionBarTransition; Loading @@ -45,6 +51,7 @@ import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; import java.util.ArrayList; import java.util.List; /** * MenuPresenter for building action menus as seen in the action bar and action modes. Loading @@ -54,6 +61,7 @@ import java.util.ArrayList; public class ActionMenuPresenter extends BaseMenuPresenter implements ActionProvider.SubUiVisibilityListener { private static final String TAG = "ActionMenuPresenter"; private static final int ITEM_ANIMATION_DURATION = 150; private OverflowMenuButton mOverflowButton; private boolean mReserveOverflow; Loading @@ -71,8 +79,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter // Group IDs that have been added as actions - used temporarily, allocated here for reuse. private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray(); private View mScrapActionButtonView; private OverflowPopup mOverflowPopup; private ActionButtonSubmenu mActionButtonPopup; Loading @@ -84,6 +90,18 @@ public class ActionMenuPresenter extends BaseMenuPresenter final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback(); int mOpenSubMenuId; // These collections are used to store pre- and post-layout information for menu items, // which is used to determine appropriate animations to run for changed items. private SparseArray<MenuItemLayoutInfo> mPreLayoutItems = new SparseArray<MenuItemLayoutInfo>(); private SparseArray<MenuItemLayoutInfo> mPostLayoutItems = new SparseArray<MenuItemLayoutInfo>(); // The list of currently running animations on menu items. private List<ItemAnimationInfo> mRunningItemAnimations = new ArrayList<ItemAnimationInfo>(); public ActionMenuPresenter(Context context) { super(context, com.android.internal.R.layout.action_menu_layout, com.android.internal.R.layout.action_menu_item_layout); Loading Loading @@ -125,9 +143,6 @@ public class ActionMenuPresenter extends BaseMenuPresenter mActionItemWidthLimit = width; mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density); // Drop a scrap view as it may no longer reflect the proper context/config. mScrapActionButtonView = null; } public void onConfigurationChanged(Configuration newConfig) { Loading Loading @@ -202,10 +217,186 @@ public class ActionMenuPresenter extends BaseMenuPresenter return item.isActionButton(); } /** * Store layout information about current items in the menu. This is stored for * both pre- and post-layout phases and compared in runItemAnimations() to determine * the animations that need to be run on any item changes. * * @param preLayout Whether this is being called in the pre-layout phase. This is passed * into the MenuItemLayoutInfo structure to store the appropriate position values. */ private void computeMenuItemAnimationInfo(boolean preLayout) { final ViewGroup menuViewParent = (ViewGroup) mMenuView; final int count = menuViewParent.getChildCount(); SparseArray items = preLayout ? mPreLayoutItems : mPostLayoutItems; for (int i = 0; i < count; ++i) { View child = menuViewParent.getChildAt(i); final int id = child.getId(); if (id > 0 && child.getWidth() != 0 && child.getHeight() != 0) { MenuItemLayoutInfo info = new MenuItemLayoutInfo(child, preLayout); items.put(id, info); } } } /** * This method is called once both the pre-layout and post-layout steps have * happened. It figures out which views are new (didn't exist prior to layout), * gone (existed pre-layout, but are now gone), or changed (exist in both, * but in a different location) and runs appropriate animations on those views. * Items are tracked by ids, since the underlying views that represent items * pre- and post-layout may be different. */ private void runItemAnimations() { for (int i = 0; i < mPreLayoutItems.size(); ++i) { int id = mPreLayoutItems.keyAt(i); final MenuItemLayoutInfo menuItemLayoutInfoPre = mPreLayoutItems.get(id); final int postLayoutIndex = mPostLayoutItems.indexOfKey(id); if (postLayoutIndex >= 0) { // item exists pre and post: see if it's changed final MenuItemLayoutInfo menuItemLayoutInfoPost = mPostLayoutItems.valueAt(postLayoutIndex); PropertyValuesHolder pvhX = null; PropertyValuesHolder pvhY = null; if (menuItemLayoutInfoPre.left != menuItemLayoutInfoPost.left) { pvhX = PropertyValuesHolder.ofFloat(View.TRANSLATION_X, (menuItemLayoutInfoPre.left - menuItemLayoutInfoPost.left), 0); } if (menuItemLayoutInfoPre.top != menuItemLayoutInfoPost.top) { pvhY = PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, menuItemLayoutInfoPre.top - menuItemLayoutInfoPost.top, 0); } if (pvhX != null || pvhY != null) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j); if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.MOVE) { oldInfo.animator.cancel(); } } ObjectAnimator anim; if (pvhX != null) { if (pvhY != null) { anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhX, pvhY); } else { anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhX); } } else { anim = ObjectAnimator.ofPropertyValuesHolder(menuItemLayoutInfoPost.view, pvhY); } anim.setDuration(ITEM_ANIMATION_DURATION); anim.start(); ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfoPost, anim, ItemAnimationInfo.MOVE); mRunningItemAnimations.add(info); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { if (mRunningItemAnimations.get(j).animator == animation) { mRunningItemAnimations.remove(j); break; } } } }); } mPostLayoutItems.remove(id); } else { // item used to be there, is now gone float oldAlpha = 1; for (int j = 0; j < mRunningItemAnimations.size(); ++j) { ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j); if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.FADE_IN) { oldAlpha = oldInfo.menuItemLayoutInfo.view.getAlpha(); oldInfo.animator.cancel(); } } ObjectAnimator anim = ObjectAnimator.ofFloat(menuItemLayoutInfoPre.view, View.ALPHA, oldAlpha, 0); // Re-using the view from pre-layout assumes no view recycling ((ViewGroup) mMenuView).getOverlay().add(menuItemLayoutInfoPre.view); anim.setDuration(ITEM_ANIMATION_DURATION); anim.start(); ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfoPre, anim, ItemAnimationInfo.FADE_OUT); mRunningItemAnimations.add(info); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { if (mRunningItemAnimations.get(j).animator == animation) { mRunningItemAnimations.remove(j); break; } } ((ViewGroup) mMenuView).getOverlay().remove(menuItemLayoutInfoPre.view); } }); } } for (int i = 0; i < mPostLayoutItems.size(); ++i) { int id = mPostLayoutItems.keyAt(i); final int postLayoutIndex = mPostLayoutItems.indexOfKey(id); if (postLayoutIndex >= 0) { // item is new final MenuItemLayoutInfo menuItemLayoutInfo = mPostLayoutItems.valueAt(postLayoutIndex); float oldAlpha = 0; for (int j = 0; j < mRunningItemAnimations.size(); ++j) { ItemAnimationInfo oldInfo = mRunningItemAnimations.get(j); if (oldInfo.id == id && oldInfo.animType == ItemAnimationInfo.FADE_OUT) { oldAlpha = oldInfo.menuItemLayoutInfo.view.getAlpha(); oldInfo.animator.cancel(); } } ObjectAnimator anim = ObjectAnimator.ofFloat(menuItemLayoutInfo.view, View.ALPHA, oldAlpha, 1); anim.start(); anim.setDuration(ITEM_ANIMATION_DURATION); ItemAnimationInfo info = new ItemAnimationInfo(id, menuItemLayoutInfo, anim, ItemAnimationInfo.FADE_IN); mRunningItemAnimations.add(info); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { for (int j = 0; j < mRunningItemAnimations.size(); ++j) { if (mRunningItemAnimations.get(j).animator == animation) { mRunningItemAnimations.remove(j); break; } } } }); } } mPreLayoutItems.clear(); mPostLayoutItems.clear(); } /** * Gets position/existence information on menu items before and after layout, * which is then fed into runItemAnimations() */ private void setupItemAnimations() { final ViewGroup menuViewParent = (ViewGroup) mMenuView; computeMenuItemAnimationInfo(true); final ViewTreeObserver observer = menuViewParent.getViewTreeObserver(); if (observer != null) { observer.addOnDrawListener(new ViewTreeObserver.OnDrawListener() { @Override public void onDraw() { computeMenuItemAnimationInfo(false); observer.removeOnDrawListener(this); runItemAnimations(); } }); } } @Override public void updateMenuView(boolean cleared) { final ViewGroup menuViewParent = (ViewGroup) ((View) mMenuView).getParent(); if (menuViewParent != null) { setupItemAnimations(); ActionBarTransition.beginDelayedTransition(menuViewParent); } super.updateMenuView(cleared); Loading Loading @@ -431,10 +622,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter MenuItemImpl item = visibleItems.get(i); if (item.requiresActionButton()) { View v = getItemView(item, mScrapActionButtonView, parent); if (mScrapActionButtonView == null) { mScrapActionButtonView = v; } View v = getItemView(item, null, parent); if (mStrictWidthLimit) { cellsRemaining -= ActionMenuView.measureChildForCells(v, cellSize, cellsRemaining, querySpec, 0); Loading @@ -460,10 +648,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter (!mStrictWidthLimit || cellsRemaining > 0); if (isAction) { View v = getItemView(item, mScrapActionButtonView, parent); if (mScrapActionButtonView == null) { mScrapActionButtonView = v; } View v = getItemView(item, null, parent); if (mStrictWidthLimit) { final int cells = ActionMenuView.measureChildForCells(v, cellSize, cellsRemaining, querySpec, 0); Loading Loading @@ -819,4 +1004,53 @@ public class ActionMenuPresenter extends BaseMenuPresenter boolean mHasTintMode; boolean mHasTintList; } /** * This class holds layout information for a menu item. This is used to determine * pre- and post-layout information about menu items, which will then be used to * determine appropriate item animations. */ private static class MenuItemLayoutInfo { View view; int left; int top; MenuItemLayoutInfo(View view, boolean preLayout) { left = view.getLeft(); top = view.getTop(); if (preLayout) { // We track translation for pre-layout because a view might be mid-animation // and we need this information to know where to animate from left += view.getTranslationX(); top += view.getTranslationY(); } this.view = view; } } /** * This class is used to store information about currently-running item animations. * This is used when new animations are scheduled to determine whether any existing * animations need to be canceled, based on whether the running animations overlap * with any new animations. For example, if an item is currently animating from * location A to B and another change dictates that it be animated to C, then the current * A-B animation will be canceled and a new animation to C will be started. */ private static class ItemAnimationInfo { int id; MenuItemLayoutInfo menuItemLayoutInfo; Animator animator; int animType; static final int MOVE = 0; static final int FADE_IN = 1; static final int FADE_OUT = 2; ItemAnimationInfo(int id, MenuItemLayoutInfo info, Animator anim, int animType) { this.id = id; menuItemLayoutInfo = info; animator = anim; this.animType = animType; } } }