Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save stormzhang/9170789 to your computer and use it in GitHub Desktop.

Select an option

Save stormzhang/9170789 to your computer and use it in GitHub Desktop.

Revisions

  1. @chrisbanes chrisbanes created this gist Feb 19, 2014.
    217 changes: 217 additions & 0 deletions ForegroundLinearLayout.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,217 @@
    /*
    * 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 your.package;

    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Rect;
    import android.graphics.drawable.Drawable;
    import android.util.AttributeSet;
    import android.view.Gravity;
    import android.widget.LinearLayout;

    import your.package.R;

    public class ForegroundLinearLayout extends LinearLayout {

    private Drawable mForeground;

    private final Rect mSelfBounds = new Rect();
    private final Rect mOverlayBounds = new Rect();

    private int mForegroundGravity = Gravity.FILL;

    protected boolean mForegroundInPadding = true;

    boolean mForegroundBoundsChanged = false;

    public ForegroundLinearLayout(Context context) {
    super(context);
    }

    public ForegroundLinearLayout(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
    }

    public ForegroundLinearLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);

    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ForegroundLinearLayout,
    defStyle, 0);

    mForegroundGravity = a.getInt(
    R.styleable.ForegroundLinearLayout_android_foregroundGravity, mForegroundGravity);

    final Drawable d = a.getDrawable(R.styleable.ForegroundLinearLayout_android_foreground);
    if (d != null) {
    setForeground(d);
    }

    mForegroundInPadding = a.getBoolean(
    R.styleable.ForegroundLinearLayout_android_foregroundInsidePadding, true);

    a.recycle();
    }

    /**
    * Describes how the foreground is positioned.
    *
    * @return foreground gravity.
    *
    * @see #setForegroundGravity(int)
    */
    public int getForegroundGravity() {
    return mForegroundGravity;
    }

    /**
    * Describes how the foreground is positioned. Defaults to START and TOP.
    *
    * @param foregroundGravity See {@link android.view.Gravity}
    *
    * @see #getForegroundGravity()
    */
    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 (mForegroundGravity == Gravity.FILL && mForeground != null) {
    Rect padding = new Rect();
    mForeground.getPadding(padding);
    }

    requestLayout();
    }
    }

    @Override
    protected boolean verifyDrawable(Drawable who) {
    return super.verifyDrawable(who) || (who == mForeground);
    }

    @Override
    public void jumpDrawablesToCurrentState() {
    super.jumpDrawablesToCurrentState();
    if (mForeground != null) mForeground.jumpToCurrentState();
    }

    @Override
    protected void drawableStateChanged() {
    super.drawableStateChanged();
    if (mForeground != null && mForeground.isStateful()) {
    mForeground.setState(getDrawableState());
    }
    }

    /**
    * 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.
    */
    public void setForeground(Drawable drawable) {
    if (mForeground != drawable) {
    if (mForeground != null) {
    mForeground.setCallback(null);
    unscheduleDrawable(mForeground);
    }

    mForeground = drawable;

    if (drawable != null) {
    setWillNotDraw(false);
    drawable.setCallback(this);
    if (drawable.isStateful()) {
    drawable.setState(getDrawableState());
    }
    if (mForegroundGravity == Gravity.FILL) {
    Rect padding = new Rect();
    drawable.getPadding(padding);
    }
    } 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;
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    mForegroundBoundsChanged = changed;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    mForegroundBoundsChanged = true;
    }

    @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 = getRight() - getLeft();
    final int h = getBottom() - getTop();

    if (mForegroundInPadding) {
    selfBounds.set(0, 0, w, h);
    } else {
    selfBounds.set(getPaddingLeft(), getPaddingTop(),
    w - getPaddingRight(), h - getPaddingBottom());
    }

    Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
    foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
    foreground.setBounds(overlayBounds);
    }

    foreground.draw(canvas);
    }
    }
    }
    10 changes: 10 additions & 0 deletions attrs.xml
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    <?xml version="1.0" encoding="utf-8"?>
    <resources>

    <declare-styleable name="ForegroundLinearLayout">
    <attr name="android:foreground" />
    <attr name="android:foregroundInsidePadding" />
    <attr name="android:foregroundGravity" />
    </declare-styleable>

    </resources>