Android自定义ViewAndroid技术知识Android进阶之路

Android之自定义View的死亡三部曲之(Layout)

2017-06-02  本文已影响96人  Angels_安杰

前言



    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 + ")");
        }
        //1、如果有一个值发生了改变,那么就需要重新调用onLayout方法了,后面会分析到
        if (mLeft != left || mRight != right || mTop != top || mBottom != bottom) {
            changed = true;

            // Remember our drawn bit
            int drawn = mPrivateFlags & PFLAG_DRAWN;

            //2、保存旧的宽和高
            int oldWidth = mRight - mLeft;
            int oldHeight = mBottom - mTop;
            //计算新的宽和高
            int newWidth = right - left;
            int newHeight = bottom - top;
            //3、判断宽高是否有分生变化
            boolean sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);

            //Invalidate our old position
            //4、如果大小变化了,在已绘制了的情况下就请求重新绘制
            invalidate(sizeChanged);

            //5、存储新的值
            mLeft = left;
            mTop = top;
            mRight = right;
            mBottom = bottom;
            mRenderNode.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom);

            mPrivateFlags |= PFLAG_HAS_BOUNDS;

            if (sizeChanged) {
                //6、大小变化时进行处理
                sizeChange(newWidth, newHeight, oldWidth, oldHeight);
             }

            if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) {
                 //7、如果此时View是可见状态下,立即执行绘制操作
                  invalidate(sizeChanged);

                }

             mPrivateFlags |= drawn;

            mBackgroundSizeChanged = true;
            if (mForegroundInfo != null) {
                mForegroundInfo.mBoundsChanged = true;
              }

            notifySubtreeAccessibilityStateChangedIfNeeded();
        }
         return changed;
    }



@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) {
    //1、获得子view的熟练
    final int count = getChildCount();
    //2、获得父view左面位置,getPaddingLeftWithForeground获得的是对应的内边距
    final int parentLeft = getPaddingLeftWithForeground();
    //3、获得父view右边位置
    final int parentRight = right - left - getPaddingRightWithForeground();
    //4、获得父view顶部位置
    final int parentTop = getPaddingTopWithForeground();
    //4、获得父view底部位置
    final int parentBottom = bottom - top - getPaddingBottomWithForeground();

    for (int i = 0; i < count; i++) {
        //5、遍历子view
        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;
             //6、针对不同的水平方向Gravity做处理
            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;
            }
            //6、针对不同的垂直方向Gravity做处理
            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;
            }
            //7、调用child的layout方法,对child进行布局,前面我们分析了
            child.layout(childLeft, childTop, childLeft + width, childTop + height);
        }
}
}

对childView进行布局

总结:

上一篇 下一篇

猜你喜欢

热点阅读