Introducing the split action bar.
Apply (or extend) the theme Theme.Holo.SplitActionBarWhenNarrow or Theme.Holo.Light.SplitActionBarWhenNarrow to enable splitting the action bar across both the top and bottom of the screen. This places the action menu along the bottom, leaving more room at the top for titles, navigation, and custom views and more room at the bottom for menu items. TODO: Refine layout of the action menu when placed at the bottom of the screen. Make action modes split as well. Change-Id: I92c91f99c533f26aecf6b828ed041386c4f16922
This commit is contained in:
@@ -1490,9 +1490,11 @@ package android {
|
||||
field public static final int Theme_Holo_Light_Dialog_NoActionBar_MinWidth = 16973942; // 0x1030076
|
||||
field public static final int Theme_Holo_Light_NoActionBar = 16974064; // 0x10300f0
|
||||
field public static final int Theme_Holo_Light_Panel = 16973948; // 0x103007c
|
||||
field public static final int Theme_Holo_Light_SplitActionBarWhenNarrow = 16974067; // 0x10300f3
|
||||
field public static final int Theme_Holo_NoActionBar = 16973932; // 0x103006c
|
||||
field public static final int Theme_Holo_NoActionBar_Fullscreen = 16973933; // 0x103006d
|
||||
field public static final int Theme_Holo_Panel = 16973947; // 0x103007b
|
||||
field public static final int Theme_Holo_SplitActionBarWhenNarrow = 16974066; // 0x10300f2
|
||||
field public static final int Theme_Holo_Wallpaper = 16973949; // 0x103007d
|
||||
field public static final int Theme_Holo_Wallpaper_NoTitleBar = 16973950; // 0x103007e
|
||||
field public static final int Theme_InputMethod = 16973908; // 0x1030054
|
||||
|
||||
@@ -2482,6 +2482,7 @@ public class Activity extends ContextThemeWrapper
|
||||
break;
|
||||
|
||||
case Window.FEATURE_ACTION_BAR:
|
||||
initActionBar();
|
||||
mActionBar.dispatchMenuVisibilityChanged(false);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ public class ActionBarImpl extends ActionBar {
|
||||
private ActionBarContainer mContainerView;
|
||||
private ActionBarView mActionView;
|
||||
private ActionBarContextView mUpperContextView;
|
||||
private LinearLayout mLowerContextView;
|
||||
private LinearLayout mLowerView;
|
||||
private View mContentView;
|
||||
private ViewGroup mExternalTabView;
|
||||
|
||||
@@ -106,8 +106,8 @@ public class ActionBarImpl extends ActionBar {
|
||||
new AnimatorListenerAdapter() { // NORMAL_VIEW
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mLowerContextView != null) {
|
||||
mLowerContextView.removeAllViews();
|
||||
if (mLowerView != null) {
|
||||
mLowerView.removeAllViews();
|
||||
}
|
||||
mCurrentModeAnim = null;
|
||||
hideAllExcept(NORMAL_VIEW);
|
||||
@@ -162,7 +162,7 @@ public class ActionBarImpl extends ActionBar {
|
||||
mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
|
||||
mUpperContextView = (ActionBarContextView) decor.findViewById(
|
||||
com.android.internal.R.id.action_context_bar);
|
||||
mLowerContextView = (LinearLayout) decor.findViewById(
|
||||
mLowerView = (LinearLayout) decor.findViewById(
|
||||
com.android.internal.R.id.lower_action_context_bar);
|
||||
mContainerView = (ActionBarContainer) decor.findViewById(
|
||||
com.android.internal.R.id.action_bar_container);
|
||||
@@ -173,8 +173,8 @@ public class ActionBarImpl extends ActionBar {
|
||||
}
|
||||
|
||||
mActionView.setContextView(mUpperContextView);
|
||||
mContextDisplayMode = mLowerContextView == null ?
|
||||
CONTEXT_DISPLAY_NORMAL : CONTEXT_DISPLAY_SPLIT;
|
||||
mContextDisplayMode = mActionView.isSplitActionBar() ?
|
||||
CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
|
||||
|
||||
if (!mActionView.hasEmbeddedTabs()) {
|
||||
HorizontalScrollView tabScroller = new HorizontalScrollView(mContext);
|
||||
@@ -348,9 +348,9 @@ public class ActionBarImpl extends ActionBar {
|
||||
mode.invalidate();
|
||||
mUpperContextView.initForMode(mode);
|
||||
animateTo(CONTEXT_VIEW);
|
||||
if (mLowerContextView != null) {
|
||||
if (mLowerView != null) {
|
||||
// TODO animate this
|
||||
mLowerContextView.setVisibility(View.VISIBLE);
|
||||
mLowerView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
mActionMode = mode;
|
||||
return mode;
|
||||
@@ -616,9 +616,9 @@ public class ActionBarImpl extends ActionBar {
|
||||
|
||||
// Clear out the context mode views after the animation finishes
|
||||
mUpperContextView.closeMode();
|
||||
if (mLowerContextView != null && mLowerContextView.getVisibility() != View.GONE) {
|
||||
if (mLowerView != null && mLowerView.getVisibility() != View.GONE) {
|
||||
// TODO Animate this
|
||||
mLowerContextView.setVisibility(View.GONE);
|
||||
mLowerView.setVisibility(View.GONE);
|
||||
}
|
||||
mActionMode = null;
|
||||
|
||||
|
||||
@@ -73,10 +73,11 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
|
||||
|
||||
int width = mWidthLimit;
|
||||
if (mReserveOverflow) {
|
||||
OverflowMenuButton button = new OverflowMenuButton(mContext);
|
||||
mOverflowButton = button;
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
mOverflowButton.measure(spec, spec);
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mContext);
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
mOverflowButton.measure(spec, spec);
|
||||
}
|
||||
width -= mOverflowButton.getMeasuredWidth();
|
||||
} else {
|
||||
mOverflowButton = null;
|
||||
@@ -88,6 +89,17 @@ public class ActionMenuPresenter extends BaseMenuPresenter {
|
||||
mScrapActionButtonView = null;
|
||||
}
|
||||
|
||||
public void setWidthLimit(int width) {
|
||||
if (mReserveOverflow) {
|
||||
width -= mOverflowButton.getMeasuredWidth();
|
||||
}
|
||||
mActionItemWidthLimit = width;
|
||||
}
|
||||
|
||||
public void setItemLimit(int itemCount) {
|
||||
mMaxItems = itemCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
MenuView result = super.getMenuView(root);
|
||||
|
||||
@@ -110,7 +110,7 @@ public class ActionBarView extends ViewGroup {
|
||||
private int mProgressStyle;
|
||||
private int mIndeterminateProgressStyle;
|
||||
|
||||
private boolean mShowMenu;
|
||||
private boolean mSplitActionBar;
|
||||
private boolean mUserTitle;
|
||||
private boolean mIncludeTabs;
|
||||
|
||||
@@ -119,6 +119,7 @@ public class ActionBarView extends ViewGroup {
|
||||
private ActionMenuPresenter mActionMenuPresenter;
|
||||
|
||||
private ActionBarContextView mContextView;
|
||||
private ViewGroup mSplitView;
|
||||
|
||||
private ActionMenuItem mLogoNavItem;
|
||||
|
||||
@@ -245,6 +246,26 @@ public class ActionBarView extends ViewGroup {
|
||||
addView(mIndeterminateProgressView);
|
||||
}
|
||||
|
||||
public void setSplitActionBar(boolean splitActionBar) {
|
||||
if (mSplitActionBar != splitActionBar) {
|
||||
if (mMenuView != null) {
|
||||
if (splitActionBar) {
|
||||
removeView(mMenuView);
|
||||
if (mSplitView != null) {
|
||||
mSplitView.addView(mMenuView);
|
||||
}
|
||||
} else {
|
||||
addView(mMenuView);
|
||||
}
|
||||
}
|
||||
mSplitActionBar = splitActionBar;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSplitActionBar() {
|
||||
return mSplitActionBar;
|
||||
}
|
||||
|
||||
public boolean hasEmbeddedTabs() {
|
||||
return mIncludeTabs;
|
||||
}
|
||||
@@ -284,10 +305,29 @@ public class ActionBarView extends ViewGroup {
|
||||
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
menuView.setLayoutParams(layoutParams);
|
||||
addView(menuView);
|
||||
if (!mSplitActionBar) {
|
||||
addView(menuView);
|
||||
} else {
|
||||
// Allow full screen width in split mode.
|
||||
mActionMenuPresenter.setWidthLimit(
|
||||
getContext().getResources().getDisplayMetrics().widthPixels);
|
||||
// No limit to the item count; use whatever will fit.
|
||||
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
|
||||
if (mSplitView != null) {
|
||||
mSplitView.addView(menuView);
|
||||
} // We'll add this later if we missed it this time.
|
||||
}
|
||||
mMenuView = menuView;
|
||||
}
|
||||
|
||||
public void setSplitView(ViewGroup splitView) {
|
||||
mSplitView = splitView;
|
||||
splitView.setVisibility(VISIBLE);
|
||||
if (mMenuView != null) {
|
||||
splitView.addView(mMenuView);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean showOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.showOverflowMenu();
|
||||
@@ -718,7 +758,7 @@ public class ActionBarView extends ViewGroup {
|
||||
leftOfCenter -= homeWidth;
|
||||
}
|
||||
|
||||
if (mMenuView != null) {
|
||||
if (mMenuView != null && mMenuView.getParent() == this) {
|
||||
availableWidth = measureChildView(mMenuView, availableWidth,
|
||||
childSpecHeight, 0);
|
||||
rightOfCenter -= mMenuView.getMeasuredWidth();
|
||||
@@ -880,7 +920,7 @@ public class ActionBarView extends ViewGroup {
|
||||
}
|
||||
|
||||
int menuLeft = r - l - getPaddingRight();
|
||||
if (mMenuView != null) {
|
||||
if (mMenuView != null && mMenuView.getParent() == this) {
|
||||
positionChildInverse(mMenuView, menuLeft, y, contentHeight);
|
||||
menuLeft -= mMenuView.getMeasuredWidth();
|
||||
}
|
||||
|
||||
@@ -47,5 +47,6 @@ This is an optimized layout for a screen with the Action Bar enabled.
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:attr/actionBarStyle"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
android:gravity="center"/>
|
||||
</LinearLayout>
|
||||
|
||||
@@ -51,5 +51,6 @@ the Action Bar enabled overlaying application content.
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
style="?android:attr/actionBarStyle"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
android:gravity="center"/>
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -19,4 +19,5 @@
|
||||
<resources>
|
||||
<bool name="allow_action_menu_item_text_with_icon">true</bool>
|
||||
<bool name="action_bar_embed_tabs">true</bool>
|
||||
<bool name="split_action_bar_is_narrow">false</bool>
|
||||
</resources>
|
||||
|
||||
@@ -299,6 +299,10 @@
|
||||
when there is not reserved space for their UI (such as an Action Bar). -->
|
||||
<attr name="windowActionModeOverlay" format="boolean" />
|
||||
|
||||
<!-- Flag indicating that the action bar should be split to provide more
|
||||
room for elements. -->
|
||||
<attr name="windowSplitActionBar" format="boolean" />
|
||||
|
||||
<!-- Defines the default soft input state that this window would
|
||||
like when it is displayed. -->
|
||||
<attr name="windowSoftInputMode">
|
||||
@@ -1429,6 +1433,7 @@
|
||||
<attr name="windowActionBar" />
|
||||
<attr name="windowActionModeOverlay" />
|
||||
<attr name="windowActionBarOverlay" />
|
||||
<attr name="windowSplitActionBar" />
|
||||
<attr name="windowEnableSplitTouch" />
|
||||
<attr name="windowCloseOnTouchOutside" />
|
||||
<!-- The minimum width the window is allowed to be, along the major
|
||||
|
||||
@@ -19,4 +19,5 @@
|
||||
<resources>
|
||||
<bool name="allow_action_menu_item_text_with_icon">false</bool>
|
||||
<bool name="action_bar_embed_tabs">false</bool>
|
||||
<bool name="split_action_bar_is_narrow">true</bool>
|
||||
</resources>
|
||||
|
||||
@@ -1660,6 +1660,8 @@
|
||||
|
||||
<public type="style" name="Theme.Holo.Light.NoActionBar" />
|
||||
<public type="style" name="TextAppearance.SuggestionHighlight" />
|
||||
<public type="style" name="Theme.Holo.SplitActionBarWhenNarrow" />
|
||||
<public type="style" name="Theme.Holo.Light.SplitActionBarWhenNarrow" />
|
||||
|
||||
<public type="attr" name="textSuggestionsWindowStyle" />
|
||||
<public type="attr" name="textEditSuggestionsBottomWindowLayout" />
|
||||
|
||||
@@ -1538,4 +1538,17 @@
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<!-- Variant of the holographic (dark) theme with an action bar that
|
||||
splits across the top and bottom of the activity when constrained
|
||||
for horizontal space. -->
|
||||
<style name="Theme.Holo.SplitActionBarWhenNarrow">
|
||||
<item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
|
||||
</style>
|
||||
|
||||
<!-- Variant of the holographic (light) theme with an action bar that
|
||||
splits across the top and bottom of the activity when constrained
|
||||
for horizontal space. -->
|
||||
<style name="Theme.Holo.Light.SplitActionBarWhenNarrow">
|
||||
<item name="android:windowSplitActionBar">@android:bool/split_action_bar_is_narrow</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -2587,6 +2587,21 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
|
||||
if ((localFeatures & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
|
||||
mActionBar.initIndeterminateProgress();
|
||||
}
|
||||
|
||||
final boolean splitActionBar = getWindowStyle().getBoolean(
|
||||
com.android.internal.R.styleable.Window_windowSplitActionBar, false);
|
||||
if (splitActionBar) {
|
||||
final ViewGroup splitView = (ViewGroup) findViewById(
|
||||
com.android.internal.R.id.lower_action_context_bar);
|
||||
if (splitView != null) {
|
||||
mActionBar.setSplitActionBar(splitActionBar);
|
||||
mActionBar.setSplitView(splitView);
|
||||
} else {
|
||||
Log.e(TAG, "Window style requested split action bar with " +
|
||||
"incompatible window decor! Ignoring request.");
|
||||
}
|
||||
}
|
||||
|
||||
// Post the panel invalidate for later; avoid application onCreateOptionsMenu
|
||||
// being called in the middle of onCreate or similar.
|
||||
mDecor.post(new Runnable() {
|
||||
|
||||
Reference in New Issue
Block a user