Loading core/java/com/android/internal/widget/ActionBarOverlayLayout.java +172 −33 Original line number Diff line number Diff line Loading @@ -16,33 +16,42 @@ package com.android.internal.widget; import android.view.ViewGroup; import com.android.internal.app.ActionBarImpl; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.FrameLayout; /** * Special layout for the containing of an overlay action bar (and its * content) to correctly handle fitting system windows when the content * has request that its layout ignore them. */ public class ActionBarOverlayLayout extends FrameLayout { public class ActionBarOverlayLayout extends ViewGroup { private int mActionBarHeight; private ActionBarImpl mActionBar; private int mWindowVisibility = View.VISIBLE; // The main UI elements that we handle the layout of. private View mContent; private View mActionBarTop; private View mActionBarBottom; // Some interior UI elements. private ActionBarContainer mContainerView; private ActionBarView mActionView; private View mActionBarBottom; private boolean mOverlayMode; private int mLastSystemUiVisibility; private final Rect mLocalInsets = new Rect(); private final Rect mBaseContentInsets = new Rect(); private final Rect mLastBaseContentInsets = new Rect(); private final Rect mContentInsets = new Rect(); private final Rect mBaseInnerInsets = new Rect(); private final Rect mInnerInsets = new Rect(); private final Rect mLastInnerInsets = new Rect(); static final int[] mActionBarSizeAttr = new int [] { com.android.internal.R.attr.actionBarSize Loading Loading @@ -139,7 +148,7 @@ public class ActionBarOverlayLayout extends FrameLayout { private boolean applyInsets(View view, Rect insets, boolean left, boolean top, boolean bottom, boolean right) { boolean changed = false; FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)view.getLayoutParams(); LayoutParams lp = (LayoutParams)view.getLayoutParams(); if (left && lp.leftMargin != insets.left) { changed = true; lp.leftMargin = insets.left; Loading Loading @@ -168,52 +177,163 @@ public class ActionBarOverlayLayout extends FrameLayout { // The top and bottom action bars are always within the content area. boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true); if (mActionBarBottom != null) { changed |= applyInsets(mActionBarBottom, insets, true, false, true, true); mBaseInnerInsets.set(insets); computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets); if (!mLastBaseContentInsets.equals(mBaseContentInsets)) { changed = true; mLastBaseContentInsets.set(mBaseContentInsets); } int topSpace = 0; if (stable || mActionBarTop.getVisibility() == VISIBLE) { // This is the space needed on top of the window for the action bar. topSpace = mActionBarHeight; if (changed) { requestLayout(); } // We don't do any more at this point. To correctly compute the content/inner // insets in all cases, we need to know the measured size of the various action // bar elements. fitSystemWindows() happens before the measure pass, so we can't // do that here. Instead we will take this up in onMeasure(). return true; } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int maxHeight = 0; int maxWidth = 0; int childState = 0; int topInset = 0; int bottomInset = 0; measureChildWithMargins(mActionBarTop, widthMeasureSpec, 0, heightMeasureSpec, 0); LayoutParams lp = (LayoutParams) mActionBarTop.getLayoutParams(); maxWidth = Math.max(maxWidth, mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, mActionBarTop.getMeasuredState()); measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0); lp = (LayoutParams) mActionBarBottom.getLayoutParams(); maxWidth = Math.max(maxWidth, mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, mActionBarBottom.getMeasuredState()); final int vis = getWindowSystemUiVisibility(); final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0; if (stable) { // This is the standard space needed for the action bar. For stable measurement, // we can't depend on the size currently reported by it -- this must remain constant. topInset = mActionBarHeight; if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) { View tabs = mContainerView.getTabContainer(); if (tabs != null && (stable || tabs.getVisibility() == VISIBLE)) { if (tabs != null) { // If tabs are not embedded, increase space on top to account for them. topSpace += mActionBarHeight; topInset += mActionBarHeight; } } } else if (mActionBarTop.getVisibility() == VISIBLE) { // This is the space needed on top of the window for all of the action bar // and tabs. topInset = mActionBarTop.getMeasuredHeight(); } int bottomSpace = 0; if (mActionView.isSplitActionBar()) { if ((mActionBarBottom != null && (stable || mActionBarBottom.getVisibility() == VISIBLE))) { // If action bar is split, adjust bottom insets for it. bottomSpace = mActionBarHeight; if (stable) { bottomInset = mActionBarHeight; } else { bottomInset = mActionBarBottom.getMeasuredHeight(); } } // If the window has not requested system UI layout flags, we need to // make sure its content is not being covered by system UI... though it // will still be covered by the action bar since they have requested it to // will still be covered by the action bar if they have requested it to // overlay. boolean res = computeFitSystemWindows(insets, mLocalInsets); mContentInsets.set(mBaseContentInsets); mInnerInsets.set(mBaseInnerInsets); if (!mOverlayMode && !stable) { mLocalInsets.top += topSpace; mLocalInsets.bottom += bottomSpace; mContentInsets.top += topInset; mContentInsets.bottom += bottomInset; } else { insets.top += topSpace; insets.bottom += bottomSpace; mInnerInsets.top += topInset; mInnerInsets.bottom += bottomInset; } changed |= applyInsets(mContent, mLocalInsets, true, true, true, true); applyInsets(mContent, mContentInsets, true, true, true, true); if (changed) { requestLayout(); if (!mLastInnerInsets.equals(mInnerInsets)) { // If the inner insets have changed, we need to dispatch this down to // the app's fitSystemWindows(). We do this before measuring the content // view to keep the same semantics as the normal fitSystemWindows() call. mLastInnerInsets.set(mInnerInsets); super.fitSystemWindows(mInnerInsets); } super.fitSystemWindows(insets); return true; measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0); lp = (LayoutParams) mContent.getLayoutParams(); maxWidth = Math.max(maxWidth, mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, mContent.getMeasuredState()); // Account for padding too maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); // Check against our minimum height and width maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int count = getChildCount(); final int parentLeft = getPaddingLeft(); final int parentRight = right - left - getPaddingRight(); final int parentTop = getPaddingTop(); final int parentBottom = bottom - top - getPaddingBottom(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int width = child.getMeasuredWidth(); final int height = child.getMeasuredHeight(); int childLeft = parentLeft + lp.leftMargin; int childTop; if (child == mActionBarBottom) { childTop = parentBottom - height - lp.bottomMargin; } else { childTop = parentTop + lp.topMargin; } child.layout(childLeft, childTop, childLeft + width, childTop + height); } } } void pullChildren() { Loading @@ -226,4 +346,23 @@ public class ActionBarOverlayLayout extends FrameLayout { mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar); } } public static class LayoutParams extends MarginLayoutParams { public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(ViewGroup.LayoutParams source) { super(source); } public LayoutParams(ViewGroup.MarginLayoutParams source) { super(source); } } } core/res/res/layout/screen_action_bar.xml +1 −3 Original line number Diff line number Diff line Loading @@ -29,8 +29,7 @@ This is an optimized layout for a screen with the Action Bar enabled. android:layout_height="match_parent" /> <LinearLayout android:id="@+id/top_action_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top"> android:layout_height="wrap_content"> <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -57,7 +56,6 @@ This is an optimized layout for a screen with the Action Bar enabled. <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" style="?android:attr/actionBarSplitStyle" android:visibility="gone" android:gravity="center"/> Loading Loading
core/java/com/android/internal/widget/ActionBarOverlayLayout.java +172 −33 Original line number Diff line number Diff line Loading @@ -16,33 +16,42 @@ package com.android.internal.widget; import android.view.ViewGroup; import com.android.internal.app.ActionBarImpl; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Rect; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.FrameLayout; /** * Special layout for the containing of an overlay action bar (and its * content) to correctly handle fitting system windows when the content * has request that its layout ignore them. */ public class ActionBarOverlayLayout extends FrameLayout { public class ActionBarOverlayLayout extends ViewGroup { private int mActionBarHeight; private ActionBarImpl mActionBar; private int mWindowVisibility = View.VISIBLE; // The main UI elements that we handle the layout of. private View mContent; private View mActionBarTop; private View mActionBarBottom; // Some interior UI elements. private ActionBarContainer mContainerView; private ActionBarView mActionView; private View mActionBarBottom; private boolean mOverlayMode; private int mLastSystemUiVisibility; private final Rect mLocalInsets = new Rect(); private final Rect mBaseContentInsets = new Rect(); private final Rect mLastBaseContentInsets = new Rect(); private final Rect mContentInsets = new Rect(); private final Rect mBaseInnerInsets = new Rect(); private final Rect mInnerInsets = new Rect(); private final Rect mLastInnerInsets = new Rect(); static final int[] mActionBarSizeAttr = new int [] { com.android.internal.R.attr.actionBarSize Loading Loading @@ -139,7 +148,7 @@ public class ActionBarOverlayLayout extends FrameLayout { private boolean applyInsets(View view, Rect insets, boolean left, boolean top, boolean bottom, boolean right) { boolean changed = false; FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams)view.getLayoutParams(); LayoutParams lp = (LayoutParams)view.getLayoutParams(); if (left && lp.leftMargin != insets.left) { changed = true; lp.leftMargin = insets.left; Loading Loading @@ -168,52 +177,163 @@ public class ActionBarOverlayLayout extends FrameLayout { // The top and bottom action bars are always within the content area. boolean changed = applyInsets(mActionBarTop, insets, true, true, false, true); if (mActionBarBottom != null) { changed |= applyInsets(mActionBarBottom, insets, true, false, true, true); mBaseInnerInsets.set(insets); computeFitSystemWindows(mBaseInnerInsets, mBaseContentInsets); if (!mLastBaseContentInsets.equals(mBaseContentInsets)) { changed = true; mLastBaseContentInsets.set(mBaseContentInsets); } int topSpace = 0; if (stable || mActionBarTop.getVisibility() == VISIBLE) { // This is the space needed on top of the window for the action bar. topSpace = mActionBarHeight; if (changed) { requestLayout(); } // We don't do any more at this point. To correctly compute the content/inner // insets in all cases, we need to know the measured size of the various action // bar elements. fitSystemWindows() happens before the measure pass, so we can't // do that here. Instead we will take this up in onMeasure(). return true; } @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int maxHeight = 0; int maxWidth = 0; int childState = 0; int topInset = 0; int bottomInset = 0; measureChildWithMargins(mActionBarTop, widthMeasureSpec, 0, heightMeasureSpec, 0); LayoutParams lp = (LayoutParams) mActionBarTop.getLayoutParams(); maxWidth = Math.max(maxWidth, mActionBarTop.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, mActionBarTop.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, mActionBarTop.getMeasuredState()); measureChildWithMargins(mActionBarBottom, widthMeasureSpec, 0, heightMeasureSpec, 0); lp = (LayoutParams) mActionBarBottom.getLayoutParams(); maxWidth = Math.max(maxWidth, mActionBarBottom.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, mActionBarBottom.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, mActionBarBottom.getMeasuredState()); final int vis = getWindowSystemUiVisibility(); final boolean stable = (vis & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0; if (stable) { // This is the standard space needed for the action bar. For stable measurement, // we can't depend on the size currently reported by it -- this must remain constant. topInset = mActionBarHeight; if (mActionBar != null && mActionBar.hasNonEmbeddedTabs()) { View tabs = mContainerView.getTabContainer(); if (tabs != null && (stable || tabs.getVisibility() == VISIBLE)) { if (tabs != null) { // If tabs are not embedded, increase space on top to account for them. topSpace += mActionBarHeight; topInset += mActionBarHeight; } } } else if (mActionBarTop.getVisibility() == VISIBLE) { // This is the space needed on top of the window for all of the action bar // and tabs. topInset = mActionBarTop.getMeasuredHeight(); } int bottomSpace = 0; if (mActionView.isSplitActionBar()) { if ((mActionBarBottom != null && (stable || mActionBarBottom.getVisibility() == VISIBLE))) { // If action bar is split, adjust bottom insets for it. bottomSpace = mActionBarHeight; if (stable) { bottomInset = mActionBarHeight; } else { bottomInset = mActionBarBottom.getMeasuredHeight(); } } // If the window has not requested system UI layout flags, we need to // make sure its content is not being covered by system UI... though it // will still be covered by the action bar since they have requested it to // will still be covered by the action bar if they have requested it to // overlay. boolean res = computeFitSystemWindows(insets, mLocalInsets); mContentInsets.set(mBaseContentInsets); mInnerInsets.set(mBaseInnerInsets); if (!mOverlayMode && !stable) { mLocalInsets.top += topSpace; mLocalInsets.bottom += bottomSpace; mContentInsets.top += topInset; mContentInsets.bottom += bottomInset; } else { insets.top += topSpace; insets.bottom += bottomSpace; mInnerInsets.top += topInset; mInnerInsets.bottom += bottomInset; } changed |= applyInsets(mContent, mLocalInsets, true, true, true, true); applyInsets(mContent, mContentInsets, true, true, true, true); if (changed) { requestLayout(); if (!mLastInnerInsets.equals(mInnerInsets)) { // If the inner insets have changed, we need to dispatch this down to // the app's fitSystemWindows(). We do this before measuring the content // view to keep the same semantics as the normal fitSystemWindows() call. mLastInnerInsets.set(mInnerInsets); super.fitSystemWindows(mInnerInsets); } super.fitSystemWindows(insets); return true; measureChildWithMargins(mContent, widthMeasureSpec, 0, heightMeasureSpec, 0); lp = (LayoutParams) mContent.getLayoutParams(); maxWidth = Math.max(maxWidth, mContent.getMeasuredWidth() + lp.leftMargin + lp.rightMargin); maxHeight = Math.max(maxHeight, mContent.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); childState = combineMeasuredStates(childState, mContent.getMeasuredState()); // Account for padding too maxWidth += getPaddingLeft() + getPaddingRight(); maxHeight += getPaddingTop() + getPaddingBottom(); // Check against our minimum height and width maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight()); maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth()); setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState), resolveSizeAndState(maxHeight, heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT)); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { final int count = getChildCount(); final int parentLeft = getPaddingLeft(); final int parentRight = right - left - getPaddingRight(); final int parentTop = getPaddingTop(); final int parentBottom = bottom - top - getPaddingBottom(); for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { final LayoutParams lp = (LayoutParams) child.getLayoutParams(); final int width = child.getMeasuredWidth(); final int height = child.getMeasuredHeight(); int childLeft = parentLeft + lp.leftMargin; int childTop; if (child == mActionBarBottom) { childTop = parentBottom - height - lp.bottomMargin; } else { childTop = parentTop + lp.topMargin; } child.layout(childLeft, childTop, childLeft + width, childTop + height); } } } void pullChildren() { Loading @@ -226,4 +346,23 @@ public class ActionBarOverlayLayout extends FrameLayout { mActionBarBottom = findViewById(com.android.internal.R.id.split_action_bar); } } public static class LayoutParams extends MarginLayoutParams { public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(ViewGroup.LayoutParams source) { super(source); } public LayoutParams(ViewGroup.MarginLayoutParams source) { super(source); } } }
core/res/res/layout/screen_action_bar.xml +1 −3 Original line number Diff line number Diff line Loading @@ -29,8 +29,7 @@ This is an optimized layout for a screen with the Action Bar enabled. android:layout_height="match_parent" /> <LinearLayout android:id="@+id/top_action_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top"> android:layout_height="wrap_content"> <com.android.internal.widget.ActionBarContainer android:id="@+id/action_bar_container" android:layout_width="match_parent" android:layout_height="wrap_content" Loading @@ -57,7 +56,6 @@ This is an optimized layout for a screen with the Action Bar enabled. <com.android.internal.widget.ActionBarContainer android:id="@+id/split_action_bar" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" style="?android:attr/actionBarSplitStyle" android:visibility="gone" android:gravity="center"/> Loading