Viewgroup measure child

理解MeasureSpec:

  • spec(規格要求,分爲 width spec 和 height spec) 是一個int型的**組合值**,包括spec mode 和 size兩個值;
  • MeasureSpec 是產生spec 的工具;
  • child 的 spec 是由其自身的佈局參數(layout_width,layout_height等)以及parent 的 spec 共同決定的

以寬度計算爲例:

childDimension_表明_layout_widthjava

  • 若是parent的 spec mode 是 exactly(即 parent的寬度是肯定的值):app

    • 若是child佈局參數layout_width 是 一個具體的值(大於 0),那麼child 的 spec mode 就是 exactly, 並且size 是_childDimension_;
    • 若是child佈局參數layout_width 是 match_content,那麼child 的 spec mode 就是 exactly, 並且size 是parent 的size
    • 若是child佈局參數layout_width 是 wrap_content,那麼child 的 spec mode 就是 at_most, 並且size 是parent 的size(不一樣的佈局容器策略會不一樣,這裏以默認的ViewGroup 爲例);
  • 若是parent的 spec mode 是 exactly(即 parent的寬度是肯定的值): * 看代碼..工具

  • 若是parent的 spec mode 是 UNSPECIFIED(即 parent的寬度是肯定的值): * 看代碼..佈局

參數解釋:

  • spec 是這個vg 的 parent 爲此 vg 賦予的 MeasureSpec
  • padding 是此 vg 的padding;
  • childDimension 是child 的 layout模式(wrap_content,即-二、match_parent,即-1) 或具體的值;

返回值是爲child 產生的 MeasureSpecui

//ViewGroup.java
     * Does the hard part of measureChildren: figuring out the MeasureSpec to
     * pass to a particular child. This method figures out the right MeasureSpec
     * for one dimension (height or width) of one child view.
     *
     * The goal is to combine information from our MeasureSpec with the
     * LayoutParams of the child to get the best possible results. For example,
     * if the this view knows its size (because its MeasureSpec has a mode of
     * EXACTLY), and the child has indicated in its LayoutParams that it wants
     * to be the same size as the parent, the parent should ask the child to
     * layout given an exact size.
     *
     * @param spec The requirements for this view
     * @param padding The padding of this view for the current dimension and
     *        margins, if applicable
     * @param childDimension How big the child wants to be in the current
     *        dimension
     * @return a MeasureSpec integer for the child
     */
    public static int getChildMeasureSpec(int spec, int padding, int childDimension) {
        int specMode = MeasureSpec.getMode(spec);
        int specSize = MeasureSpec.getSize(spec);

        int size = Math.max(0, specSize - padding);

        int resultSize = 0;
        int resultMode = 0;

        switch (specMode) {
        // Parent has imposed an exact size on us
        case MeasureSpec.EXACTLY:
            if (childDimension >= 0) {
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size. So be it.
                resultSize = size;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent has imposed a maximum size on us
        case MeasureSpec.AT_MOST:
            if (childDimension >= 0) {
                // Child wants a specific size... so be it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size, but our size is not fixed.
                // Constrain child to not be bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size. It can't be
                // bigger than us.
                resultSize = size;
                resultMode = MeasureSpec.AT_MOST;
            }
            break;

        // Parent asked to see how big we want to be
        case MeasureSpec.UNSPECIFIED:
            if (childDimension >= 0) {
                // Child wants a specific size... let him have it
                resultSize = childDimension;
                resultMode = MeasureSpec.EXACTLY;
            } else if (childDimension == LayoutParams.MATCH_PARENT) {
                // Child wants to be our size... find out how big it should
                // be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = View.sUseZeroUnspecifiedMeasureSpec ? 0 : size;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }
相關文章
相關標籤/搜索