强制ViewAnimator将第一个子节点用于布局大小

时间:2012-08-22 06:58:40

标签: android android-layout

我有ViewAnimator,其中包含两个子视图。我希望ViewAnimator的大小与第一个孩子一样大,无论哪个孩子当前活跃。这有可能通过一些配置,还是我必须实现自己的子类并覆盖onMeasure等?

1 个答案:

答案 0 :(得分:1)

我最终通过扩展ViewAnimator,覆盖onMeasure并将布局的尺寸设置为第一个孩子的尺寸来解决此问题。这就是我想出来的。它基本上是FrameLayout.onMeasure方法的一个小修改。

/**
 * Overrides the default {@link android.widget.FrameLayout#onMeasure(int, int)}
 * behavior to allow a main child to be defined which determines the size of the
 * layout. By default, the max size of all children is used as the layout size.
 */
public class SizePinnedViewAnimator extends ViewAnimator {
    private final int mainChildIndex;

    @SuppressWarnings("UnusedDeclaration")
    public SizePinnedViewAnimator(final Context context) {
        super(context);
        mainChildIndex = 0;
    }

    @SuppressWarnings("UnusedDeclaration")
    public SizePinnedViewAnimator(final Context context, final AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(
                attrs,
                R.styleable.SizePinnedViewAnimator);
        mainChildIndex = a.getInt(R.styleable.SizePinnedViewAnimator_mainChild, 0);
        a.recycle();
    }

    /**
     * {@inheritDoc}
     *
     * Copied from {@link android.widget.FrameLayout#onMeasure(int, int)}
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int count = getChildCount();

        View mainChild = getChildAt(mainChildIndex);
        if(mainChild == null) {
            throw new IllegalStateException("No child at index " + mainChildIndex);
        }

        measureChildWithMargins(mainChild, widthMeasureSpec, 0, heightMeasureSpec, 0);

        int maxHeight = mainChild.getMeasuredHeight();
        int maxWidth = mainChild.getMeasuredWidth();

        widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST);
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST);

        // Find rightmost and bottommost child
        for (int i = 0; i < count; i++) {
            if(i == mainChildIndex) continue;

            final View child = getChildAt(i);
            if (getConsiderGoneChildrenWhenMeasuring() || child.getVisibility() != GONE) {
                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
            }
        }

        // Don't have access to the foreground padding numbers, but we're not
        // using a foreground drawable anyway, so ignore it.

        // Account for padding too
        maxWidth += getPaddingLeft() + getPaddingRight();
        maxHeight += getPaddingTop() + getPaddingBottom();

        // Check against our minimum height and width
        maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
        maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());

        setMeasuredDimension(resolveSize(maxWidth, widthMeasureSpec),
                resolveSize(maxHeight, heightMeasureSpec));
    }
}

res/values/attrs.xml中定义的属性:

<declare-styleable name="SizePinnedViewAnimator">
    <attr name="mainChild" format="integer" />
</declare-styleable>