android中关于布局

来源:互联网 发布:h5电商源码 编辑:程序博客网 时间:2024/06/01 10:37

View中的onLayout方法用于子类重写,设置view的位置;

以FrameLayout为例子:

   /**     * {@inheritDoc}     */    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        layoutChildren(left, top, right, bottom, false /* no force left gravity */);    }

 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();        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);            }        }    }

child的layout方法设置孩子位置;

layout方法用于给当前view和它的孩子设置 大小和位置;

  /**     * Assign a size and position to a view and all of its     * descendants     *     * <p>This is the second phase of the layout mechanism.     * (The first is measuring). In this phase, each parent calls     * layout on all of its children to position them.     * This is typically done using the child measurements     * that were stored in the measure pass().</p>     *     * <p>Derived classes should not override this method.     * Derived classes with children should override     * onLayout. In that method, they should     * call layout on each of their children.</p>     *     * @param l Left position, relative to parent     * @param t Top position, relative to parent     * @param r Right position, relative to parent     * @param b Bottom position, relative to parent     */    @SuppressWarnings({"unchecked"})    public void layout(int l, int t, int r, int b) {        if ((mPrivateFlags3 & PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT) != 0) {            onMeasure(mOldWidthMeasureSpec, mOldHeightMeasureSpec);            mPrivateFlags3 &= ~PFLAG3_MEASURE_NEEDED_BEFORE_LAYOUT;        }        int oldL = mLeft;        int oldT = mTop;        int oldB = mBottom;        int oldR = mRight;        boolean changed = isLayoutModeOptical(mParent) ?                setOpticalFrame(l, t, r, b) : setFrame(l, t, r, b);        if (changed || (mPrivateFlags & PFLAG_LAYOUT_REQUIRED) == PFLAG_LAYOUT_REQUIRED) {            onLayout(changed, l, t, r, b);            mPrivateFlags &= ~PFLAG_LAYOUT_REQUIRED;            ListenerInfo li = mListenerInfo;            if (li != null && li.mOnLayoutChangeListeners != null) {                ArrayList<OnLayoutChangeListener> listenersCopy =                        (ArrayList<OnLayoutChangeListener>)li.mOnLayoutChangeListeners.clone();                int numListeners = listenersCopy.size();                for (int i = 0; i < numListeners; ++i) {                    listenersCopy.get(i).onLayoutChange(this, l, t, r, b, oldL, oldT, oldR, oldB);                }            }        }        mPrivateFlags &= ~PFLAG_FORCE_LAYOUT;        mPrivateFlags3 |= PFLAG3_IS_LAID_OUT;    }
看setFrame方法: 这个方法是设置view的位置和刷新绘制的;

    /**     * Assign a size and position to this view.     *     * This is called from layout.     *     * @param left Left position, relative to parent     * @param top Top position, relative to parent     * @param right Right position, relative to parent     * @param bottom Bottom position, relative to parent     * @return true if the new size and position are different than the     *         previous ones     * {@hide}     */    protected boolean setFrame(int left, int top, int right, int bottom) {        boolean changed = false;        if (DBG) {            Log.d("View", this + " View.setFrame(" + left + "," + top + ","                    + right + "," + bottom + ")");        }        //布局第一次调用的时候,肯定会执行下面的方法,mLeft mRight mTop, mBottom都是0;        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {            changed = true;            // Remember our drawn bit            int drawn = mPrivateFlags & PFLAG_DRAWN;            int oldWidth = mRight - mLeft;            int oldHeight = mBottom - mTop;            int newWidth = right - left;            int newHeight = bottom - top;            boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);            // Invalidate our old position           // 这是刷新旧的位置的视图绘制;           invalidate(sizeChanged);            mLeft = left;            mTop = top;            mRight = right;            mBottom = bottom;            mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);            mPrivateFlags |= PFLAG_HAS_BOUNDS;            //onSizeChanged方法此时会调用;            if (sizeChanged) {                sizeChange(newWidth, newHeight, oldWidth, oldHeight);            }            if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) {                // If we are visible, force the DRAWN bit to on so that                // this invalidate will go through (at least to our parent).                // This is because someone may have invalidated this view                // before this call to setFrame came in, thereby clearing                // the DRAWN bit.              ' //上面解释了mPrivatedFlags设置的原因;  强制设置DRAWN bit位 开启,以便于这个刷新通过,  因为在我们调用setFrame方法之前,或许已经inValidated                //视图,导致mPrivateFlags被重置, 因此需要清除the DRAWN bit;               mPrivateFlags |= PFLAG_DRAWN;                invalidate(sizeChanged);                // parent display list may need to be recreated based on a change in the bounds                // of any child                invalidateParentCaches();            }            // Reset drawn bit to original value (invalidate turns it off)            mPrivateFlags |= drawn;            mBackgroundSizeChanged = true;            if (mForegroundInfo != null) {                mForegroundInfo.mBoundsChanged = true;            }            notifySubtreeAccessibilityStateChangedIfNeeded();        }        return changed;    }


0 0
原创粉丝点击