Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 76d8f968 authored by Adam Powell's avatar Adam Powell
Browse files

Add content insets to Toolbar

Content insets allow a Toolbar to define horizontal gridlines for the
start/end or left/right edges of major content (not counting the
navigation button or menu). This allows apps to align their layout
content above or below a Toolbar with the title and other contents of
the bar by using app-defined measurements.

Change-Id: Ibd7e0810bf81070eb5f59a42ad3257f35bc0156a
parent 0a3103e7
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -417,6 +417,10 @@ package android {
    field public static final int content = 16843355; // 0x101025b
    field public static final int contentAuthority = 16843408; // 0x1010290
    field public static final int contentDescription = 16843379; // 0x1010273
    field public static final int contentInsetEnd = 16843861; // 0x1010455
    field public static final int contentInsetLeft = 16843862; // 0x1010456
    field public static final int contentInsetRight = 16843863; // 0x1010457
    field public static final int contentInsetStart = 16843860; // 0x1010454
    field public static final int controlX1 = 16843799; // 0x1010417
    field public static final int controlX2 = 16843801; // 0x1010419
    field public static final int controlY1 = 16843800; // 0x1010418
@@ -36952,6 +36956,10 @@ package android.widget {
    ctor public Toolbar(android.content.Context, android.util.AttributeSet);
    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int, int);
    method public int getContentInsetEnd();
    method public int getContentInsetLeft();
    method public int getContentInsetRight();
    method public int getContentInsetStart();
    method public android.graphics.drawable.Drawable getLogo();
    method public java.lang.CharSequence getLogoDescription();
    method public android.view.Menu getMenu();
@@ -36960,6 +36968,8 @@ package android.widget {
    method public java.lang.CharSequence getTitle();
    method public void inflateMenu(int);
    method protected void onLayout(boolean, int, int, int, int);
    method public void setContentInsetsAbsolute(int, int);
    method public void setContentInsetsRelative(int, int);
    method public void setLogo(int);
    method public void setLogo(android.graphics.drawable.Drawable);
    method public void setLogoDescription(int);
+91 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package android.widget;

/**
 * RtlSpacingHelper manages the relationship between left/right and start/end for views
 * that need to maintain both absolute and relative settings for a form of spacing similar
 * to view padding.
 */
class RtlSpacingHelper {
    public static final int UNDEFINED = Integer.MIN_VALUE;

    private int mLeft = 0;
    private int mRight = 0;
    private int mStart = UNDEFINED;
    private int mEnd = UNDEFINED;
    private int mExplicitLeft = 0;
    private int mExplicitRight = 0;

    private boolean mIsRtl = false;
    private boolean mIsRelative = false;

    public int getLeft() {
        return mLeft;
    }

    public int getRight() {
        return mRight;
    }

    public int getStart() {
        return mIsRtl ? mRight : mLeft;
    }

    public int getEnd() {
        return mIsRtl ? mLeft : mRight;
    }

    public void setRelative(int start, int end) {
        mStart = start;
        mEnd = end;
        mIsRelative = true;
        if (mIsRtl) {
            if (end != UNDEFINED) mLeft = end;
            if (start != UNDEFINED) mRight = start;
        } else {
            if (start != UNDEFINED) mLeft = start;
            if (end != UNDEFINED) mRight = end;
        }
    }

    public void setAbsolute(int left, int right) {
        mIsRelative = false;
        if (left != UNDEFINED) mLeft = mExplicitLeft = left;
        if (right != UNDEFINED) mRight = mExplicitRight = right;
    }

    public void setDirection(boolean isRtl) {
        if (isRtl == mIsRtl) {
            return;
        }
        mIsRtl = isRtl;
        if (mIsRelative) {
            if (isRtl) {
                mLeft = mEnd != UNDEFINED ? mEnd : mExplicitLeft;
                mRight = mStart != UNDEFINED ? mStart : mExplicitRight;
            } else {
                mLeft = mStart != UNDEFINED ? mStart : mExplicitLeft;
                mRight = mEnd != UNDEFINED ? mEnd : mExplicitRight;
            }
        } else {
            mLeft = mExplicitLeft;
            mRight = mExplicitRight;
        }
    }
}
+156 −4
Original line number Diff line number Diff line
@@ -88,11 +88,14 @@ public class Toolbar extends ViewGroup {

    private int mTitleTextAppearance;
    private int mSubtitleTextAppearance;

    private int mTitleMarginStart;
    private int mTitleMarginEnd;
    private int mTitleMarginTop;
    private int mTitleMarginBottom;

    private final RtlSpacingHelper mContentInsets = new RtlSpacingHelper();

    private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;

    private CharSequence mTitleText;
@@ -135,8 +138,8 @@ public class Toolbar extends ViewGroup {
        mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
        mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
        mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
        mTitleMarginStart = mTitleMarginEnd = Math.max(0, a.getDimensionPixelOffset(
                R.styleable.Toolbar_titleMargins, -1));
        mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
                a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);

        final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
        if (marginStart >= 0) {
@@ -159,6 +162,24 @@ public class Toolbar extends ViewGroup {
            mTitleMarginBottom = marginBottom;
        }

        final int contentInsetStart =
                a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
                        RtlSpacingHelper.UNDEFINED);
        final int contentInsetEnd =
                a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetEnd,
                        RtlSpacingHelper.UNDEFINED);
        final int contentInsetLeft =
                a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetLeft, 0);
        final int contentInsetRight =
                a.getDimensionPixelSize(R.styleable.Toolbar_contentInsetRight, 0);

        mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);

        if (contentInsetStart != RtlSpacingHelper.UNDEFINED ||
                contentInsetEnd != RtlSpacingHelper.UNDEFINED) {
            mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
        }

        final CharSequence title = a.getText(R.styleable.Toolbar_title);
        if (!TextUtils.isEmpty(title)) {
            setTitle(title);
@@ -171,6 +192,12 @@ public class Toolbar extends ViewGroup {
        a.recycle();
    }

    @Override
    public void onRtlPropertiesChanged(@ResolvedLayoutDir int layoutDirection) {
        super.onRtlPropertiesChanged(layoutDirection);
        mContentInsets.setDirection(layoutDirection == LAYOUT_DIRECTION_RTL);
    }

    /**
     * Set a logo drawable from a resource id.
     *
@@ -489,6 +516,122 @@ public class Toolbar extends ViewGroup {
        mOnMenuItemClickListener = listener;
    }

    /**
     * Set the content insets for this toolbar relative to layout direction.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @param contentInsetStart Content inset for the toolbar starting edge
     * @param contentInsetEnd Content inset for the toolbar ending edge
     *
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public void setContentInsetsRelative(int contentInsetStart, int contentInsetEnd) {
        mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
    }

    /**
     * Get the starting content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The starting content inset for this toolbar
     *
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public int getContentInsetStart() {
        return mContentInsets.getStart();
    }

    /**
     * Get the ending content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The ending content inset for this toolbar
     *
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public int getContentInsetEnd() {
        return mContentInsets.getEnd();
    }

    /**
     * Set the content insets for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @param contentInsetLeft Content inset for the toolbar's left edge
     * @param contentInsetRight Content inset for the toolbar's right edge
     *
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     * @see #getContentInsetRight()
     */
    public void setContentInsetsAbsolute(int contentInsetLeft, int contentInsetRight) {
        mContentInsets.setAbsolute(contentInsetLeft, contentInsetRight);
    }

    /**
     * Get the left content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The left content inset for this toolbar
     *
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetRight()
     */
    public int getContentInsetLeft() {
        return mContentInsets.getLeft();
    }

    /**
     * Get the right content inset for this toolbar.
     *
     * <p>The content inset affects the valid area for Toolbar content other than
     * the navigation button and menu. Insets define the minimum margin for these components
     * and can be used to effectively align Toolbar content along well-known gridlines.</p>
     *
     * @return The right content inset for this toolbar
     *
     * @see #setContentInsetsRelative(int, int)
     * @see #setContentInsetsAbsolute(int, int)
     * @see #getContentInsetStart()
     * @see #getContentInsetEnd()
     * @see #getContentInsetLeft()
     */
    public int getContentInsetRight() {
        return mContentInsets.getRight();
    }

    private void ensureNavButtonView() {
        if (mNavButtonView == null) {
            mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
@@ -522,22 +665,28 @@ public class Toolbar extends ViewGroup {

        // System views measure first.

        int navWidth = 0;
        if (shouldLayout(mNavButtonView)) {
            measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
            width += mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
            navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
            height = Math.max(height, mNavButtonView.getMeasuredHeight() +
                    getVerticalMargins(mNavButtonView));
            childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
        }

        width += Math.max(getContentInsetStart(), navWidth);

        int menuWidth = 0;
        if (shouldLayout(mMenuView)) {
            measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
            width += mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
            menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
            height = Math.max(height, mMenuView.getMeasuredHeight() +
                    getVerticalMargins(mMenuView));
            childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
        }

        width += Math.max(getContentInsetEnd(), menuWidth);

        if (shouldLayout(mLogoView)) {
            measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
            width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
@@ -627,6 +776,9 @@ public class Toolbar extends ViewGroup {
            }
        }

        left = Math.max(left, getContentInsetLeft());
        right = Math.min(right, width - paddingRight - getContentInsetRight());

        if (shouldLayout(mLogoView)) {
            if (isRtl) {
                right = layoutChildRight(mLogoView, right);
+1 −1
Original line number Diff line number Diff line
@@ -268,7 +268,7 @@ public class WindowDecorActionBar extends ActionBar implements
            if (getNavigationMode() == NAVIGATION_MODE_TABS) {
                tabScroller.setVisibility(View.VISIBLE);
                if (mOverlayLayout != null) {
                    mOverlayLayout.requestFitSystemWindows();
                    mOverlayLayout.requestApplyInsets();
                }
            } else {
                tabScroller.setVisibility(View.GONE);
+4 −0
Original line number Diff line number Diff line
@@ -6655,6 +6655,10 @@
        <attr name="titleMarginEnd" format="dimension" />
        <attr name="titleMarginTop" format="dimension" />
        <attr name="titleMarginBottom" format="dimension" />
        <attr name="contentInsetStart" format="dimension" />
        <attr name="contentInsetEnd" format="dimension" />
        <attr name="contentInsetLeft" format="dimension" />
        <attr name="contentInsetRight" format="dimension" />
    </declare-styleable>

    <declare-styleable name="Toolbar_LayoutParams">
Loading