diff options
| author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
|---|---|---|
| committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 19:31:44 -0800 |
| commit | 9066cfe9886ac131c34d59ed0e2d287b0e3c0087 (patch) | |
| tree | d88beb88001f2482911e3d28e43833b50e4b4e97 /core/java/android/widget/FrameLayout.java | |
| parent | d83a98f4ce9cfa908f5c54bbd70f03eec07e7553 (diff) | |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'core/java/android/widget/FrameLayout.java')
| -rw-r--r-- | core/java/android/widget/FrameLayout.java | 450 |
1 files changed, 450 insertions, 0 deletions
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java new file mode 100644 index 000000000000..8aafee2118f9 --- /dev/null +++ b/core/java/android/widget/FrameLayout.java @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2006 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; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.Region; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.view.Gravity; +import android.widget.RemoteViews.RemoteView; + + +/** + * FrameLayout is designed to block out an area on the screen to display + * a single item. You can add multiple children to a FrameLayout, but all + * children are pegged to the top left of the screen. + * Children are drawn in a stack, with the most recently added child on top. + * The size of the frame layout is the size of its largest child (plus padding), visible + * or not (if the FrameLayout's parent permits). Views that are GONE are used for sizing + * 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 +public class FrameLayout extends ViewGroup { + boolean mMeasureAllChildren = false; + + private Drawable mForeground; + private int mForegroundPaddingLeft = 0; + private int mForegroundPaddingTop = 0; + private int mForegroundPaddingRight = 0; + private int mForegroundPaddingBottom = 0; + + private final Rect mSelfBounds = new Rect(); + private final Rect mOverlayBounds = new Rect(); + private int mForegroundGravity = Gravity.FILL; + + public FrameLayout(Context context) { + super(context); + } + + public FrameLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public FrameLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout, + defStyle, 0); + + 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); + } + + mForegroundGravity = a.getInt(com.android.internal.R.styleable.FrameLayout_foregroundGravity, + mForegroundGravity); + + a.recycle(); + } + + /** + * Describes how the foreground is positioned. Defaults to FILL. + * + * @param foregroundGravity See {@link android.view.Gravity} + * + * @attr ref android.R.styleable#FrameLayout_foregroundGravity + */ + @android.view.RemotableViewMethod + public void setForegroundGravity(int foregroundGravity) { + if (mForegroundGravity != foregroundGravity) { + if ((foregroundGravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) { + foregroundGravity |= Gravity.LEFT; + } + + if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { + foregroundGravity |= Gravity.TOP; + } + + mForegroundGravity = foregroundGravity; + requestLayout(); + } + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean verifyDrawable(Drawable who) { + return super.verifyDrawable(who) || (who == mForeground); + } + + /** + * {@inheritDoc} + */ + @Override + protected void drawableStateChanged() { + super.drawableStateChanged(); + if (mForeground != null && mForeground.isStateful()) { + mForeground.setState(getDrawableState()); + } + } + + /** + * Returns a set of layout parameters with a width of + * {@link android.view.ViewGroup.LayoutParams#FILL_PARENT}, + * and a height of {@link android.view.ViewGroup.LayoutParams#FILL_PARENT}. + */ + @Override + protected LayoutParams generateDefaultLayoutParams() { + return new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_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 drawable The Drawable to be drawn on top of the children. + * + * @attr ref android.R.styleable#FrameLayout_foreground + */ + public void setForeground(Drawable drawable) { + if (mForeground != drawable) { + if (mForeground != null) { + mForeground.setCallback(null); + unscheduleDrawable(mForeground); + } + + mForeground = drawable; + mForegroundPaddingLeft = 0; + mForegroundPaddingTop = 0; + mForegroundPaddingRight = 0; + mForegroundPaddingBottom = 0; + + if (drawable != null) { + setWillNotDraw(false); + drawable.setCallback(this); + if (drawable.isStateful()) { + drawable.setState(getDrawableState()); + } + Rect padding = new Rect(); + if (drawable.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; + } + + /** + * {@inheritDoc} + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + final int count = getChildCount(); + + int maxHeight = 0; + int maxWidth = 0; + + // Find rightmost and bottommost child + for (int i = 0; i < count; i++) { + final View child = getChildAt(i); + if (mMeasureAllChildren || child.getVisibility() != GONE) { + measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); + maxWidth = Math.max(maxWidth, child.getMeasuredWidth()); + maxHeight = Math.max(maxHeight, child.getMeasuredHeight()); + } + } + + // Account for padding too + maxWidth += mPaddingLeft + mPaddingRight + mForegroundPaddingLeft + mForegroundPaddingRight; + maxHeight += mPaddingTop + mPaddingBottom + mForegroundPaddingTop + mForegroundPaddingBottom; + + // 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(resolveSize(maxWidth, widthMeasureSpec), + resolveSize(maxHeight, heightMeasureSpec)); + } + + /** + * {@inheritDoc} + */ + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + final int count = getChildCount(); + + final int parentLeft = mPaddingLeft + mForegroundPaddingLeft; + final int parentRight = right - left - mPaddingRight - mForegroundPaddingRight; + + final int parentTop = mPaddingTop + mForegroundPaddingTop; + final int parentBottom = bottom - top - mPaddingBottom - mForegroundPaddingBottom; + + 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; + int childTop = parentTop; + + final int gravity = lp.gravity; + + if (gravity != -1) { + final int horizontalGravity = gravity & Gravity.HORIZONTAL_GRAVITY_MASK; + final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK; + + switch (horizontalGravity) { + case Gravity.LEFT: + childLeft = parentLeft + lp.leftMargin; + break; + case Gravity.CENTER_HORIZONTAL: + childLeft = parentLeft + (parentRight - parentLeft + lp.leftMargin + + lp.rightMargin - width) / 2; + break; + case Gravity.RIGHT: + childLeft = parentRight - width - lp.rightMargin; + break; + default: + childLeft = parentLeft + lp.leftMargin; + } + + switch (verticalGravity) { + case Gravity.TOP: + childTop = parentTop + lp.topMargin; + break; + case Gravity.CENTER_VERTICAL: + childTop = parentTop + (parentBottom - parentTop + lp.topMargin + + lp.bottomMargin - height) / 2; + break; + case Gravity.BOTTOM: + childTop = parentBottom - height - lp.bottomMargin; + break; + default: + childTop = parentTop + lp.topMargin; + } + } + + child.layout(childLeft, childTop, childLeft + width, childTop + height); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + final Drawable foreground = mForeground; + if (foreground != null) { + final Rect selfBounds = mSelfBounds; + final Rect overlayBounds = mOverlayBounds; + + selfBounds.set(0, 0, w, h); + Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(), + foreground.getIntrinsicHeight(), selfBounds, overlayBounds); + + foreground.setBounds(overlayBounds); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + if (mForeground != null) { + mForeground.draw(canvas); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean gatherTransparentRegion(Region region) { + boolean opaque = super.gatherTransparentRegion(region); + if (region != null && mForeground != null) { + applyDrawableToTransparentRegion(mForeground, region); + } + return opaque; + } + + /** + * Determines whether to measure all children or just those in + * the VISIBLE or INVISIBLE state when measuring. Defaults to false. + * @param measureAll true to consider children marked GONE, false otherwise. + * Default value is false. + * + * @attr ref android.R.styleable#FrameLayout_measureAllChildren + */ + @android.view.RemotableViewMethod + public void setMeasureAllChildren(boolean measureAll) { + mMeasureAllChildren = measureAll; + } + + /** + * Determines whether to measure all children or just those in + * the VISIBLE or INVISIBLE state when measuring. + */ + public boolean getConsiderGoneChildrenWhenMeasuring() { + return mMeasureAllChildren; + } + + /** + * {@inheritDoc} + */ + @Override + public LayoutParams generateLayoutParams(AttributeSet attrs) { + return new FrameLayout.LayoutParams(getContext(), attrs); + } + + /** + * {@inheritDoc} + */ + @Override + protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { + return p instanceof LayoutParams; + } + + @Override + protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { + return new LayoutParams(p); + } + + /** + * Per-child layout information for layouts that support margins. + * See {@link android.R.styleable#FrameLayout_Layout FrameLayout Layout Attributes} + * for a list of all child view attributes that this class supports. + */ + public static class LayoutParams extends MarginLayoutParams { + /** + * The gravity to apply with the View to which these layout parameters + * are associated. + * + * @see android.view.Gravity + */ + public int gravity = -1; + + /** + * {@inheritDoc} + */ + public LayoutParams(Context c, AttributeSet attrs) { + super(c, attrs); + + TypedArray a = c.obtainStyledAttributes(attrs, com.android.internal.R.styleable.FrameLayout_Layout); + gravity = a.getInt(com.android.internal.R.styleable.FrameLayout_Layout_layout_gravity, -1); + a.recycle(); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(int width, int height) { + super(width, height); + } + + /** + * Creates a new set of layout parameters with the specified width, height + * and weight. + * + * @param width the width, either {@link #FILL_PARENT}, + * {@link #WRAP_CONTENT} or a fixed size in pixels + * @param height the height, either {@link #FILL_PARENT}, + * {@link #WRAP_CONTENT} or a fixed size in pixels + * @param gravity the gravity + * + * @see android.view.Gravity + */ + public LayoutParams(int width, int height, int gravity) { + super(width, height); + this.gravity = gravity; + } + + /** + * {@inheritDoc} + */ + public LayoutParams(ViewGroup.LayoutParams source) { + super(source); + } + + /** + * {@inheritDoc} + */ + public LayoutParams(ViewGroup.MarginLayoutParams source) { + super(source); + } + } +} + |
