diff options
| author | Adam Powell <adamp@google.com> | 2015-03-23 16:33:32 -0700 |
|---|---|---|
| committer | Adam Powell <adamp@google.com> | 2015-03-24 16:19:20 -0700 |
| commit | 2b25e2eee032a23fd20a136d5a747098f8b6452f (patch) | |
| tree | ebd81a4f89a8a550ab8b4de58ea09e5cd0da7911 /core/java/android | |
| parent | 4d24b14d129871692b4c844d71e0179d0403e3a4 (diff) | |
| download | frameworks_base-2b25e2eee032a23fd20a136d5a747098f8b6452f.zip frameworks_base-2b25e2eee032a23fd20a136d5a747098f8b6452f.tar.gz frameworks_base-2b25e2eee032a23fd20a136d5a747098f8b6452f.tar.bz2 | |
Move foreground drawable down from FrameLayout into View
This will allow any View to include foreground drawables. This is
useful for cases where a foreground drawable is a more appropriate
place to put a state list to show focus or touch highlighting.
Also add View#onDrawForeground as a public API hook for drawing
decorations after primary view content and child views such as
scrollbars, foreground drawables and EdgeEffects.
Change-Id: If1e4700af69db6876970f8f4ad5e3eab11b8034c
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/view/View.java | 339 | ||||
| -rw-r--r-- | core/java/android/widget/FrameLayout.java | 326 |
2 files changed, 339 insertions, 326 deletions
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f5de8e3..c29b5c9 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -3168,6 +3168,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private Drawable mBackground; private TintInfo mBackgroundTint; + @ViewDebug.ExportedProperty(deepExport = true, prefix = "fg_") + private ForegroundInfo mForegroundInfo; + /** * RenderNode used for backgrounds. * <p> @@ -3182,13 +3185,23 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private String mTransitionName; - private static class TintInfo { + static class TintInfo { ColorStateList mTintList; PorterDuff.Mode mTintMode; boolean mHasTintMode; boolean mHasTintList; } + private static class ForegroundInfo { + private Drawable mDrawable; + private TintInfo mTintInfo; + private int mGravity = Gravity.START | Gravity.TOP; + private boolean mInsidePadding = true; + private boolean mBoundsChanged; + private final Rect mSelfBounds = new Rect(); + private final Rect mOverlayBounds = new Rect(); + } + static class ListenerInfo { /** * Listener used to dispatch focus change events. @@ -4056,6 +4069,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback, setOutlineProviderFromAttribute(a.getInt(R.styleable.View_outlineProvider, PROVIDER_BACKGROUND)); break; + case R.styleable.View_foreground: + setForeground(a.getDrawable(attr)); + break; + case R.styleable.View_foregroundGravity: + setForegroundGravity(a.getInt(attr, Gravity.NO_GRAVITY)); + break; + case R.styleable.View_foregroundTintMode: + setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null)); + break; + case R.styleable.View_foregroundTint: + setForegroundTintList(a.getColorStateList(attr)); + break; + case R.styleable.View_foregroundInsidePadding: + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + mForegroundInfo.mInsidePadding = a.getBoolean(attr, + mForegroundInfo.mInsidePadding); + break; } } @@ -8801,6 +8833,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (dr != null && visible != dr.isVisible()) { dr.setVisible(visible, false); } + final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (fg != null && visible != fg.isVisible()) { + fg.setVisible(visible, false); + } } /** @@ -9917,6 +9953,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } final AttachInfo ai = mAttachInfo; if (ai != null) { @@ -10755,6 +10794,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -10820,6 +10862,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -10879,6 +10924,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -10935,6 +10983,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); } mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } invalidateParentIfNeeded(); if ((mPrivateFlags2 & PFLAG2_VIEW_QUICK_REJECTED) == PFLAG2_VIEW_QUICK_REJECTED) { // View was rejected last time it was drawn by its parent; this may have changed @@ -15313,13 +15364,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Step 4, draw the children dispatchDraw(canvas); - // Step 6, draw decorations (scrollbars) - onDrawScrollBars(canvas); - + // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } + // Step 6, draw decorations (foreground, scrollbars) + onDrawForeground(canvas); + // we're done... return; } @@ -15461,12 +15513,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, canvas.restoreToCount(saveCount); - // Step 6, draw decorations (scrollbars) - onDrawScrollBars(canvas); - + // Overlay is part of the content and draws beneath Foreground if (mOverlay != null && !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } + + // Step 6, draw decorations (foreground, scrollbars) + onDrawForeground(canvas); } /** @@ -15849,6 +15902,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, mPrivateFlags |= drawn; mBackgroundSizeChanged = true; + if (mForegroundInfo != null) { + mForegroundInfo.mBoundsChanged = true; + } notifySubtreeAccessibilityStateChangedIfNeeded(); } @@ -15992,6 +16048,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mBackground != null) { mBackground.setLayoutDirection(layoutDirection); } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.setLayoutDirection(layoutDirection); + } mPrivateFlags2 |= PFLAG2_DRAWABLE_RESOLVED; onResolveDrawables(layoutDirection); } @@ -16047,7 +16106,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @CallSuper protected boolean verifyDrawable(Drawable who) { - return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who); + return who == mBackground || (mScrollCache != null && mScrollCache.scrollBar == who) + || (mForegroundInfo != null && mForegroundInfo.mDrawable == who); } /** @@ -16065,9 +16125,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, protected void drawableStateChanged() { final int[] state = getDrawableState(); - final Drawable d = mBackground; - if (d != null && d.isStateful()) { - d.setState(state); + final Drawable bg = mBackground; + if (bg != null && bg.isStateful()) { + bg.setState(state); + } + + final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (fg != null && fg.isStateful()) { + fg.setState(state); } if (mScrollCache != null) { @@ -16099,6 +16164,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mBackground != null) { mBackground.setHotspot(x, y); } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.setHotspot(x, y); + } dispatchDrawableHotspotChanged(x, y); } @@ -16270,6 +16338,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, if (mStateListAnimator != null) { mStateListAnimator.jumpToCurrentState(); } + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.jumpToCurrentState(); + } } /** @@ -16554,6 +16625,248 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Returns the drawable used as the foreground of this View. The + * foreground drawable, if non-null, is always drawn on top of the view's content. + * + * @return a Drawable or null if no foreground was set + * + * @see #onDrawForeground(Canvas) + */ + public Drawable getForeground() { + return mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + } + + /** + * Supply a Drawable that is to be rendered on top of all of the content in the view. + * + * @param foreground the Drawable to be drawn on top of the children + * + * @attr ref android.R.styleable#View_foreground + */ + public void setForeground(Drawable foreground) { + if (mForegroundInfo == null) { + if (foreground == null) { + // Nothing to do. + return; + } + mForegroundInfo = new ForegroundInfo(); + } + + if (foreground == mForegroundInfo.mDrawable) { + // Nothing to do + return; + } + + if (mForegroundInfo.mDrawable != null) { + mForegroundInfo.mDrawable.setCallback(null); + unscheduleDrawable(mForegroundInfo.mDrawable); + } + + mForegroundInfo.mDrawable = foreground; + if (foreground != null) { + setWillNotDraw(false); + foreground.setCallback(this); + foreground.setLayoutDirection(getLayoutDirection()); + if (foreground.isStateful()) { + foreground.setState(getDrawableState()); + } + applyForegroundTint(); + } + requestLayout(); + invalidate(); + } + + /** + * Magic bit used to support features of framework-internal window decor implementation details. + * This used to live exclusively in FrameLayout. + * + * @return true if the foreground should draw inside the padding region or false + * if it should draw inset by the view's padding + * @hide internal use only; only used by FrameLayout and internal screen layouts. + */ + public boolean isForegroundInsidePadding() { + return mForegroundInfo != null ? mForegroundInfo.mInsidePadding : true; + } + + /** + * Describes how the foreground is positioned. + * + * @return foreground gravity. + * + * @see #setForegroundGravity(int) + * + * @attr ref android.R.styleable#View_foregroundGravity + */ + public int getForegroundGravity() { + return mForegroundInfo != null ? mForegroundInfo.mGravity + : Gravity.START | Gravity.TOP; + } + + /** + * Describes how the foreground is positioned. Defaults to START and TOP. + * + * @param gravity see {@link android.view.Gravity} + * + * @see #getForegroundGravity() + * + * @attr ref android.R.styleable#View_foregroundGravity + */ + public void setForegroundGravity(int gravity) { + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + + if (mForegroundInfo.mGravity != gravity) { + if ((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.START; + } + + if ((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { + gravity |= Gravity.TOP; + } + + mForegroundInfo.mGravity = gravity; + requestLayout(); + } + } + + /** + * Applies a tint to the foreground drawable. Does not modify the current tint + * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. + * <p> + * Subsequent calls to {@link #setForeground(Drawable)} will automatically + * mutate the drawable and apply the specified tint and tint mode using + * {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#View_foregroundTint + * @see #getForegroundTintList() + * @see Drawable#setTintList(ColorStateList) + */ + public void setForegroundTintList(@Nullable ColorStateList tint) { + if (mForegroundInfo == null) { + mForegroundInfo = new ForegroundInfo(); + } + if (mForegroundInfo.mTintInfo == null) { + mForegroundInfo.mTintInfo = new TintInfo(); + } + mForegroundInfo.mTintInfo.mTintList = tint; + mForegroundInfo.mTintInfo.mHasTintList = true; + + applyForegroundTint(); + } + + /** + * Return the tint applied to the foreground drawable, if specified. + * + * @return the tint applied to the foreground drawable + * @attr ref android.R.styleable#View_foregroundTint + * @see #setForegroundTintList(ColorStateList) + */ + @Nullable + public ColorStateList getForegroundTintList() { + return mForegroundInfo != null && mForegroundInfo.mTintInfo != null + ? mBackgroundTint.mTintList : null; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setForegroundTintList(ColorStateList)}} to the background + * drawable. The default mode is {@link PorterDuff.Mode#SRC_IN}. + * + * @param tintMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * @attr ref android.R.styleable#View_foregroundTintMode + * @see #getForegroundTintMode() + * @see Drawable#setTintMode(PorterDuff.Mode) + */ + public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { + if (mBackgroundTint == null) { + mBackgroundTint = new TintInfo(); + } + mBackgroundTint.mTintMode = tintMode; + mBackgroundTint.mHasTintMode = true; + + applyBackgroundTint(); + } + + /** + * Return the blending mode used to apply the tint to the foreground + * drawable, if specified. + * + * @return the blending mode used to apply the tint to the foreground + * drawable + * @attr ref android.R.styleable#View_foregroundTintMode + * @see #setBackgroundTintMode(PorterDuff.Mode) + */ + @Nullable + public PorterDuff.Mode getForegroundTintMode() { + return mForegroundInfo != null && mForegroundInfo.mTintInfo != null + ? mForegroundInfo.mTintInfo.mTintMode : null; + } + + private void applyForegroundTint() { + if (mForegroundInfo != null && mForegroundInfo.mDrawable != null + && mForegroundInfo.mTintInfo != null) { + final TintInfo tintInfo = mForegroundInfo.mTintInfo; + if (tintInfo.mHasTintList || tintInfo.mHasTintMode) { + mForegroundInfo.mDrawable = mForegroundInfo.mDrawable.mutate(); + + if (tintInfo.mHasTintList) { + mForegroundInfo.mDrawable.setTintList(tintInfo.mTintList); + } + + if (tintInfo.mHasTintMode) { + mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode); + } + + // The drawable (or one of its children) may not have been + // stateful before applying the tint, so let's try again. + if (mForegroundInfo.mDrawable.isStateful()) { + mForegroundInfo.mDrawable.setState(getDrawableState()); + } + } + } + } + + /** + * Draw any foreground content for this view. + * + * <p>Foreground content may consist of scroll bars, a {@link #setForeground foreground} + * drawable or other view-specific decorations. The foreground is drawn on top of the + * primary view content.</p> + * + * @param canvas canvas to draw into + */ + public void onDrawForeground(Canvas canvas) { + onDrawScrollBars(canvas); + + final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (foreground != null) { + if (mForegroundInfo.mBoundsChanged) { + mForegroundInfo.mBoundsChanged = false; + final Rect selfBounds = mForegroundInfo.mSelfBounds; + final Rect overlayBounds = mForegroundInfo.mOverlayBounds; + + if (mForegroundInfo.mInsidePadding) { + selfBounds.set(0, 0, getWidth(), getHeight()); + } else { + selfBounds.set(getPaddingLeft(), getPaddingTop(), + getWidth() - getPaddingRight(), getHeight() - getPaddingBottom()); + } + + final int ld = getLayoutDirection(); + Gravity.apply(mForegroundInfo.mGravity, foreground.getIntrinsicWidth(), + foreground.getIntrinsicHeight(), selfBounds, overlayBounds, ld); + foreground.setBounds(overlayBounds); + } + + foreground.draw(canvas); + } + } + + /** * Sets the padding. The view may add on the space required to display * the scrollbars, depending on the style and visibility of the scrollbars. * So the values returned from {@link #getPaddingLeft}, {@link #getPaddingTop}, @@ -18090,6 +18403,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // parts from this transparent region. applyDrawableToTransparentRegion(mBackground, region); } + final Drawable foreground = mForegroundInfo != null ? mForegroundInfo.mDrawable : null; + if (foreground != null) { + applyDrawableToTransparentRegion(mForegroundInfo.mDrawable, region); + } } return true; } diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java index f6d198b..0602944 100644 --- a/core/java/android/widget/FrameLayout.java +++ b/core/java/android/widget/FrameLayout.java @@ -53,8 +53,6 @@ import com.android.internal.R; * only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()} * is set to true. * - * @attr ref android.R.styleable#FrameLayout_foreground - * @attr ref android.R.styleable#FrameLayout_foregroundGravity * @attr ref android.R.styleable#FrameLayout_measureAllChildren */ @RemoteView @@ -64,13 +62,6 @@ public class FrameLayout extends ViewGroup { @ViewDebug.ExportedProperty(category = "measurement") boolean mMeasureAllChildren = false; - @ViewDebug.ExportedProperty(category = "drawing") - private Drawable mForeground; - private ColorStateList mForegroundTintList = null; - private PorterDuff.Mode mForegroundTintMode = null; - private boolean mHasForegroundTint = false; - private boolean mHasForegroundTintMode = false; - @ViewDebug.ExportedProperty(category = "padding") private int mForegroundPaddingLeft = 0; @@ -85,15 +76,6 @@ public class FrameLayout extends ViewGroup { private final Rect mSelfBounds = new Rect(); private final Rect mOverlayBounds = new Rect(); - - @ViewDebug.ExportedProperty(category = "drawing") - private int mForegroundGravity = Gravity.FILL; - - /** {@hide} */ - @ViewDebug.ExportedProperty(category = "drawing") - protected boolean mForegroundInPadding = true; - - boolean mForegroundBoundsChanged = false; private final ArrayList<View> mMatchParentChildren = new ArrayList<View>(1); @@ -115,48 +97,12 @@ public class FrameLayout extends ViewGroup { final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.FrameLayout, defStyleAttr, defStyleRes); - - mForegroundGravity = a.getInt( - com.android.internal.R.styleable.FrameLayout_foregroundGravity, mForegroundGravity); - - final Drawable d = a.getDrawable(com.android.internal.R.styleable.FrameLayout_foreground); - if (d != null) { - setForeground(d); - } if (a.getBoolean(com.android.internal.R.styleable.FrameLayout_measureAllChildren, false)) { setMeasureAllChildren(true); } - if (a.hasValue(R.styleable.FrameLayout_foregroundTintMode)) { - mForegroundTintMode = Drawable.parseTintMode(a.getInt( - R.styleable.FrameLayout_foregroundTintMode, -1), mForegroundTintMode); - mHasForegroundTintMode = true; - } - - if (a.hasValue(R.styleable.FrameLayout_foregroundTint)) { - mForegroundTintList = a.getColorStateList(R.styleable.FrameLayout_foregroundTint); - mHasForegroundTint = true; - } - - mForegroundInPadding = a.getBoolean(R.styleable.FrameLayout_foregroundInsidePadding, true); - a.recycle(); - - applyForegroundTint(); - } - - /** - * Describes how the foreground is positioned. - * - * @return foreground gravity. - * - * @see #setForegroundGravity(int) - * - * @attr ref android.R.styleable#FrameLayout_foregroundGravity - */ - public int getForegroundGravity() { - return mForegroundGravity; } /** @@ -166,25 +112,18 @@ public class FrameLayout extends ViewGroup { * * @see #getForegroundGravity() * - * @attr ref android.R.styleable#FrameLayout_foregroundGravity + * @attr ref android.R.styleable#View_foregroundGravity */ @android.view.RemotableViewMethod public void setForegroundGravity(int foregroundGravity) { - if (mForegroundGravity != foregroundGravity) { - if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.START; - } - - if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { - foregroundGravity |= Gravity.TOP; - } - - mForegroundGravity = foregroundGravity; - + if (getForegroundGravity() != foregroundGravity) { + super.setForegroundGravity(foregroundGravity); - if (mForegroundGravity == Gravity.FILL && mForeground != null) { + // calling get* again here because the set above may apply default constraints + final Drawable foreground = getForeground(); + if (getForegroundGravity() == Gravity.FILL && foreground != null) { Rect padding = new Rect(); - if (mForeground.getPadding(padding)) { + if (foreground.getPadding(padding)) { mForegroundPaddingLeft = padding.left; mForegroundPaddingTop = padding.top; mForegroundPaddingRight = padding.right; @@ -201,53 +140,6 @@ public class FrameLayout extends ViewGroup { } } - @Override - protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) { - super.onVisibilityChanged(changedView, visibility); - - final Drawable dr = mForeground; - if (dr != null) { - final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE; - if (visible != dr.isVisible()) { - dr.setVisible(visible, false); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - protected boolean verifyDrawable(Drawable who) { - return super.verifyDrawable(who) || (who == mForeground); - } - - @Override - public void jumpDrawablesToCurrentState() { - super.jumpDrawablesToCurrentState(); - if (mForeground != null) mForeground.jumpToCurrentState(); - } - - /** - * {@inheritDoc} - */ - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - if (mForeground != null && mForeground.isStateful()) { - mForeground.setState(getDrawableState()); - } - } - - @Override - public void drawableHotspotChanged(float x, float y) { - super.drawableHotspotChanged(x, y); - - if (mForeground != null) { - mForeground.setHotspot(x, y); - } - } - /** * Returns a set of layout parameters with a width of * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}, @@ -258,161 +150,23 @@ public class FrameLayout extends ViewGroup { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } - /** - * Supply a Drawable that is to be rendered on top of all of the child - * views in the frame layout. Any padding in the Drawable will be taken - * into account by ensuring that the children are inset to be placed - * inside of the padding area. - * - * @param d The Drawable to be drawn on top of the children. - * - * @attr ref android.R.styleable#FrameLayout_foreground - */ - public void setForeground(Drawable d) { - if (mForeground != d) { - if (mForeground != null) { - mForeground.setCallback(null); - unscheduleDrawable(mForeground); - } - - mForeground = d; - mForegroundPaddingLeft = 0; - mForegroundPaddingTop = 0; - mForegroundPaddingRight = 0; - mForegroundPaddingBottom = 0; - - if (d != null) { - setWillNotDraw(false); - d.setCallback(this); - d.setLayoutDirection(getLayoutDirection()); - if (d.isStateful()) { - d.setState(getDrawableState()); - } - applyForegroundTint(); - if (mForegroundGravity == Gravity.FILL) { - Rect padding = new Rect(); - if (d.getPadding(padding)) { - mForegroundPaddingLeft = padding.left; - mForegroundPaddingTop = padding.top; - mForegroundPaddingRight = padding.right; - mForegroundPaddingBottom = padding.bottom; - } - } - } else { - setWillNotDraw(true); - } - requestLayout(); - invalidate(); - } - } - - /** - * Returns the drawable used as the foreground of this FrameLayout. The - * foreground drawable, if non-null, is always drawn on top of the children. - * - * @return A Drawable or null if no foreground was set. - */ - public Drawable getForeground() { - return mForeground; - } - - /** - * Applies a tint to the foreground drawable. Does not modify the current - * tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default. - * <p> - * Subsequent calls to {@link #setForeground(Drawable)} will automatically - * mutate the drawable and apply the specified tint and tint mode using - * {@link Drawable#setTintList(ColorStateList)}. - * - * @param tint the tint to apply, may be {@code null} to clear tint - * - * @attr ref android.R.styleable#FrameLayout_foregroundTint - * @see #getForegroundTintList() - * @see Drawable#setTintList(ColorStateList) - */ - public void setForegroundTintList(@Nullable ColorStateList tint) { - mForegroundTintList = tint; - mHasForegroundTint = true; - - applyForegroundTint(); - } - - /** - * @return the tint applied to the foreground drawable - * @attr ref android.R.styleable#FrameLayout_foregroundTint - * @see #setForegroundTintList(ColorStateList) - */ - @Nullable - public ColorStateList getForegroundTintList() { - return mForegroundTintList; - } - - /** - * Specifies the blending mode used to apply the tint specified by - * {@link #setForegroundTintList(ColorStateList)}} to the foreground drawable. - * The default mode is {@link PorterDuff.Mode#SRC_IN}. - * - * @param tintMode the blending mode used to apply the tint, may be - * {@code null} to clear tint - * @attr ref android.R.styleable#FrameLayout_foregroundTintMode - * @see #getForegroundTintMode() - * @see Drawable#setTintMode(PorterDuff.Mode) - */ - public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) { - mForegroundTintMode = tintMode; - mHasForegroundTintMode = true; - - applyForegroundTint(); - } - - /** - * @return the blending mode used to apply the tint to the foreground - * drawable - * @attr ref android.R.styleable#FrameLayout_foregroundTintMode - * @see #setForegroundTintMode(PorterDuff.Mode) - */ - @Nullable - public PorterDuff.Mode getForegroundTintMode() { - return mForegroundTintMode; - } - - private void applyForegroundTint() { - if (mForeground != null && (mHasForegroundTint || mHasForegroundTintMode)) { - mForeground = mForeground.mutate(); - - if (mHasForegroundTint) { - mForeground.setTintList(mForegroundTintList); - } - - if (mHasForegroundTintMode) { - mForeground.setTintMode(mForegroundTintMode); - } - - // The drawable (or one of its children) may not have been - // stateful before applying the tint, so let's try again. - if (mForeground.isStateful()) { - mForeground.setState(getDrawableState()); - } - } - } - int getPaddingLeftWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) : + return isForegroundInsidePadding() ? Math.max(mPaddingLeft, mForegroundPaddingLeft) : mPaddingLeft + mForegroundPaddingLeft; } int getPaddingRightWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) : + return isForegroundInsidePadding() ? Math.max(mPaddingRight, mForegroundPaddingRight) : mPaddingRight + mForegroundPaddingRight; } private int getPaddingTopWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingTop, mForegroundPaddingTop) : + return isForegroundInsidePadding() ? Math.max(mPaddingTop, mForegroundPaddingTop) : mPaddingTop + mForegroundPaddingTop; } private int getPaddingBottomWithForeground() { - return mForegroundInPadding ? Math.max(mPaddingBottom, mForegroundPaddingBottom) : + return isForegroundInsidePadding() ? Math.max(mPaddingBottom, mForegroundPaddingBottom) : mPaddingBottom + mForegroundPaddingBottom; } @@ -527,8 +281,6 @@ public class FrameLayout extends ViewGroup { final int parentTop = getPaddingTopWithForeground(); final int parentBottom = bottom - top - getPaddingBottomWithForeground(); - mForegroundBoundsChanged = true; - for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (child.getVisibility() != GONE) { @@ -585,62 +337,6 @@ public class FrameLayout extends ViewGroup { } /** - * {@inheritDoc} - */ - @Override - protected void onSizeChanged(int w, int h, int oldw, int oldh) { - super.onSizeChanged(w, h, oldw, oldh); - mForegroundBoundsChanged = true; - } - - /** - * {@inheritDoc} - */ - @Override - public void draw(Canvas canvas) { - super.draw(canvas); - - if (mForeground != null) { - final Drawable foreground = mForeground; - - if (mForegroundBoundsChanged) { - mForegroundBoundsChanged = false; - final Rect selfBounds = mSelfBounds; - final Rect overlayBounds = mOverlayBounds; - - final int w = mRight-mLeft; - final int h = mBottom-mTop; - - if (mForegroundInPadding) { - selfBounds.set(0, 0, w, h); - } else { - selfBounds.set(mPaddingLeft, mPaddingTop, w - mPaddingRight, h - mPaddingBottom); - } - - final int layoutDirection = getLayoutDirection(); - Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), - foreground.getIntrinsicHeight(), selfBounds, overlayBounds, - layoutDirection); - foreground.setBounds(overlayBounds); - } - - foreground.draw(canvas); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean gatherTransparentRegion(Region region) { - boolean opaque = super.gatherTransparentRegion(region); - if (region != null && mForeground != null) { - applyDrawableToTransparentRegion(mForeground, region); - } - return opaque; - } - - /** * Sets whether to consider all children, or just those in * the VISIBLE or INVISIBLE state, when measuring. Defaults to false. * |
