FrameLayoutpublic class FrameLayout extends android.view.ViewGroup FrameLayout is designed to block out an area on the screen to display
a single item. Generally, FrameLayout should be used to hold a single child view, because it can
be difficult to organize child views in a way that's scalable to different screen sizes without
the children overlapping each other. You can, however, add multiple children to a FrameLayout
and control their position within the FrameLayout by assigning gravity to each child, using the
{@code
android:layout_gravity} attribute.
Child views are drawn in a stack, with the most recently added child on top.
The size of the FrameLayout is the size of its largest child (plus padding), visible
or not (if the FrameLayout's parent permits). Views that are {@link android.view.View#GONE} are
used for sizing
only if {@link #setMeasureAllChildren(boolean) setConsiderGoneChildrenWhenMeasuring()}
is set to true. |
Fields Summary |
---|
private static final int | DEFAULT_CHILD_GRAVITY | boolean | mMeasureAllChildren | private android.graphics.drawable.Drawable | mForeground | private android.content.res.ColorStateList | mForegroundTintList | private PorterDuff.Mode | mForegroundTintMode | private boolean | mHasForegroundTint | private boolean | mHasForegroundTintMode | private int | mForegroundPaddingLeft | private int | mForegroundPaddingTop | private int | mForegroundPaddingRight | private int | mForegroundPaddingBottom | private final android.graphics.Rect | mSelfBounds | private final android.graphics.Rect | mOverlayBounds | private int | mForegroundGravity | protected boolean | mForegroundInPadding{@hide} | boolean | mForegroundBoundsChanged | private final ArrayList | mMatchParentChildren |
Constructors Summary |
---|
public FrameLayout(android.content.Context context)
super(context);
| public FrameLayout(android.content.Context context, android.util.AttributeSet attrs)
this(context, attrs, 0);
| public FrameLayout(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr)
this(context, attrs, defStyleAttr, 0);
| public FrameLayout(android.content.Context context, android.util.AttributeSet attrs, int defStyleAttr, int defStyleRes)
super(context, attrs, defStyleAttr, defStyleRes);
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();
|
Methods Summary |
---|
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());
}
}
| protected boolean | checkLayoutParams(ViewGroup.LayoutParams p){@inheritDoc}
return p instanceof LayoutParams;
| public void | draw(android.graphics.Canvas canvas){@inheritDoc}
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);
}
| public void | drawableHotspotChanged(float x, float y)
super.drawableHotspotChanged(x, y);
if (mForeground != null) {
mForeground.setHotspot(x, y);
}
| protected void | drawableStateChanged(){@inheritDoc}
super.drawableStateChanged();
if (mForeground != null && mForeground.isStateful()) {
mForeground.setState(getDrawableState());
}
| public boolean | gatherTransparentRegion(android.graphics.Region region){@inheritDoc}
boolean opaque = super.gatherTransparentRegion(region);
if (region != null && mForeground != null) {
applyDrawableToTransparentRegion(mForeground, region);
}
return opaque;
| protected android.widget.FrameLayout$LayoutParams | generateDefaultLayoutParams()Returns a set of layout parameters with a width of
{@link android.view.ViewGroup.LayoutParams#MATCH_PARENT},
and a height of {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}.
return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
| public android.widget.FrameLayout$LayoutParams | generateLayoutParams(android.util.AttributeSet attrs){@inheritDoc}
return new FrameLayout.LayoutParams(getContext(), attrs);
| protected ViewGroup.LayoutParams | generateLayoutParams(ViewGroup.LayoutParams p)
return new LayoutParams(p);
| public boolean | getConsiderGoneChildrenWhenMeasuring()Determines whether all children, or just those in the VISIBLE or
INVISIBLE state, are considered when measuring.
return getMeasureAllChildren();
| public android.graphics.drawable.Drawable | getForeground()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 mForeground;
| public int | getForegroundGravity()Describes how the foreground is positioned.
return mForegroundGravity;
| public android.content.res.ColorStateList | getForegroundTintList()
return mForegroundTintList;
| public PorterDuff.Mode | getForegroundTintMode()
return mForegroundTintMode;
| public boolean | getMeasureAllChildren()Determines whether all children, or just those in the VISIBLE or
INVISIBLE state, are considered when measuring.
return mMeasureAllChildren;
| private int | getPaddingBottomWithForeground()
return mForegroundInPadding ? Math.max(mPaddingBottom, mForegroundPaddingBottom) :
mPaddingBottom + mForegroundPaddingBottom;
| int | getPaddingLeftWithForeground()
return mForegroundInPadding ? Math.max(mPaddingLeft, mForegroundPaddingLeft) :
mPaddingLeft + mForegroundPaddingLeft;
| int | getPaddingRightWithForeground()
return mForegroundInPadding ? Math.max(mPaddingRight, mForegroundPaddingRight) :
mPaddingRight + mForegroundPaddingRight;
| private int | getPaddingTopWithForeground()
return mForegroundInPadding ? Math.max(mPaddingTop, mForegroundPaddingTop) :
mPaddingTop + mForegroundPaddingTop;
| public void | jumpDrawablesToCurrentState()
super.jumpDrawablesToCurrentState();
if (mForeground != null) mForeground.jumpToCurrentState();
| void | layoutChildren(int left, int top, int right, int bottom, boolean forceLeftGravity)
final int count = getChildCount();
final int parentLeft = getPaddingLeftWithForeground();
final int parentRight = right - left - getPaddingRightWithForeground();
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) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
final int width = child.getMeasuredWidth();
final int height = child.getMeasuredHeight();
int childLeft;
int childTop;
int gravity = lp.gravity;
if (gravity == -1) {
gravity = DEFAULT_CHILD_GRAVITY;
}
final int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = parentLeft + (parentRight - parentLeft - width) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.RIGHT:
if (!forceLeftGravity) {
childLeft = parentRight - width - lp.rightMargin;
break;
}
case Gravity.LEFT:
default:
childLeft = parentLeft + lp.leftMargin;
}
switch (verticalGravity) {
case Gravity.TOP:
childTop = parentTop + lp.topMargin;
break;
case Gravity.CENTER_VERTICAL:
childTop = parentTop + (parentBottom - parentTop - height) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = parentBottom - height - lp.bottomMargin;
break;
default:
childTop = parentTop + lp.topMargin;
}
child.layout(childLeft, childTop, childLeft + width, childTop + height);
}
}
| public void | onInitializeAccessibilityEvent(android.view.accessibility.AccessibilityEvent event)
super.onInitializeAccessibilityEvent(event);
event.setClassName(FrameLayout.class.getName());
| public void | onInitializeAccessibilityNodeInfo(android.view.accessibility.AccessibilityNodeInfo info)
super.onInitializeAccessibilityNodeInfo(info);
info.setClassName(FrameLayout.class.getName());
| protected void | onLayout(boolean changed, int left, int top, int right, int bottom){@inheritDoc}
layoutChildren(left, top, right, bottom, false /* no force left gravity */);
| protected void | onMeasure(int widthMeasureSpec, int heightMeasureSpec){@inheritDoc}
int count = getChildCount();
final boolean measureMatchParentChildren =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY ||
MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;
mMatchParentChildren.clear();
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (mMeasureAllChildren || child.getVisibility() != GONE) {
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
if (measureMatchParentChildren) {
if (lp.width == LayoutParams.MATCH_PARENT ||
lp.height == LayoutParams.MATCH_PARENT) {
mMatchParentChildren.add(child);
}
}
}
}
// Account for padding too
maxWidth += getPaddingLeftWithForeground() + getPaddingRightWithForeground();
maxHeight += getPaddingTopWithForeground() + getPaddingBottomWithForeground();
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
// Check against our foreground's minimum height and width
final Drawable drawable = getForeground();
if (drawable != null) {
maxHeight = Math.max(maxHeight, drawable.getMinimumHeight());
maxWidth = Math.max(maxWidth, drawable.getMinimumWidth());
}
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
count = mMatchParentChildren.size();
if (count > 1) {
for (int i = 0; i < count; i++) {
final View child = mMatchParentChildren.get(i);
final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
int childWidthMeasureSpec;
int childHeightMeasureSpec;
if (lp.width == LayoutParams.MATCH_PARENT) {
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth() -
getPaddingLeftWithForeground() - getPaddingRightWithForeground() -
lp.leftMargin - lp.rightMargin,
MeasureSpec.EXACTLY);
} else {
childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
getPaddingLeftWithForeground() + getPaddingRightWithForeground() +
lp.leftMargin + lp.rightMargin,
lp.width);
}
if (lp.height == LayoutParams.MATCH_PARENT) {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight() -
getPaddingTopWithForeground() - getPaddingBottomWithForeground() -
lp.topMargin - lp.bottomMargin,
MeasureSpec.EXACTLY);
} else {
childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
getPaddingTopWithForeground() + getPaddingBottomWithForeground() +
lp.topMargin + lp.bottomMargin,
lp.height);
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}
| protected void | onSizeChanged(int w, int h, int oldw, int oldh){@inheritDoc}
super.onSizeChanged(w, h, oldw, oldh);
mForegroundBoundsChanged = true;
| public void | setForeground(android.graphics.drawable.Drawable d)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.
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();
}
| public void | setForegroundGravity(int foregroundGravity)Describes how the foreground is positioned. Defaults to START and TOP.
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 (mForegroundGravity == Gravity.FILL && mForeground != null) {
Rect padding = new Rect();
if (mForeground.getPadding(padding)) {
mForegroundPaddingLeft = padding.left;
mForegroundPaddingTop = padding.top;
mForegroundPaddingRight = padding.right;
mForegroundPaddingBottom = padding.bottom;
}
} else {
mForegroundPaddingLeft = 0;
mForegroundPaddingTop = 0;
mForegroundPaddingRight = 0;
mForegroundPaddingBottom = 0;
}
requestLayout();
}
| public void | setForegroundTintList(android.content.res.ColorStateList tint)Applies a tint to the foreground drawable. Does not modify the current
tint mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
Subsequent calls to {@link #setForeground(Drawable)} will automatically
mutate the drawable and apply the specified tint and tint mode using
{@link Drawable#setTintList(ColorStateList)}.
mForegroundTintList = tint;
mHasForegroundTint = true;
applyForegroundTint();
| public void | setForegroundTintMode(PorterDuff.Mode tintMode)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}.
mForegroundTintMode = tintMode;
mHasForegroundTintMode = true;
applyForegroundTint();
| public void | setMeasureAllChildren(boolean measureAll)Sets whether to consider all children, or just those in
the VISIBLE or INVISIBLE state, when measuring. Defaults to false.
mMeasureAllChildren = measureAll;
| public void | setVisibility(int visibility)
super.setVisibility(visibility);
if (mForeground != null) {
mForeground.setVisible(visibility == VISIBLE, false);
}
| public boolean | shouldDelayChildPressedState()
return false;
| protected boolean | verifyDrawable(android.graphics.drawable.Drawable who){@inheritDoc}
return super.verifyDrawable(who) || (who == mForeground);
|
|