zoukankan      html  css  js  c++  java
  • android自定义控件(一)MeasureSpec 与 ListView.onMeasure

    A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement

    for either the width or the height. A MeasureSpec is comprised of a size and a mode. There are three possible modes:

    UNSPECIFIED
      The parent has not imposed any constraint on the child. It can be whatever size it wants.
    EXACTLY
      The parent has determined an exact size for the child. The child is going to be given those bounds regardless of how big it wants to be.
    AT_MOST
      The child can be as large as it wants up to the specified size.

    1.使用 View.resolveSize(int size,int measureSpec)

    public static int resolveSize(int size, int measureSpec) {
            int result = size;
            int specMode = MeasureSpec.getMode(measureSpec);
            int specSize =  MeasureSpec.getSize(measureSpec);
            switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                result = size;
                break;
            case MeasureSpec.AT_MOST:
                result = Math.min(size, specSize);
                break;
            case MeasureSpec.EXACTLY:
                result = specSize;
                break;
            }
            return result;
        }

    2.源码

        public static class MeasureSpec {
            private static final int MODE_SHIFT = 30;
            private static final int MODE_MASK  = 0x3 << MODE_SHIFT;
    
            
            public static final int UNSPECIFIED = 0 << MODE_SHIFT;
    
            public static final int EXACTLY     = 1 << MODE_SHIFT;
    
            public static final int AT_MOST     = 2 << MODE_SHIFT;
    
            
    
            public static int  makeMeasureSpec(int size, int mode) {
                return size + mode;
            }
    
    
            public static int  getMode(int measureSpec) {
                return (measureSpec & MODE_MASK);
            }
    
            public static int  getSize(int measureSpec) {
                return (measureSpec & ~MODE_MASK);
            }
    
    
        }

    示例:

    int measureSpec = makeMeasureSpec(4, EXACTLY);
    getSize(measureSpec);
    getMode(measureSpec);

    -----------------------makeMeasureSpec --------------------- mode+size

    mode:            1000  0000  0000  0000  0000  0000  0000  000
    size:                                       100
    measureSpec: 1000  0000  0000  0000  0000  0000  0000  100


    ---------------getMode  ---------------- MODE_MASK & measureSpec

    MODE_MASK:  1100  0000  0000  0000  0000  0000  0000  0000
    measureSpec:  1000  0000  0000  0000  0000  0000  0000  100

      

    3.示例ListView.measureItem(View child)

    private void measureItem(View child) {
            ViewGroup.LayoutParams p = child.getLayoutParams();
            if (p == null) {
                p = new ViewGroup.LayoutParams(
                        ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
            }
    
            int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
                    mListPadding.left + mListPadding.right, p.width);
            int lpHeight = p.height;
            int childHeightSpec;
            if (lpHeight > 0) {
                childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
            } else {
                childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            }
            child.measure(childWidthSpec, childHeightSpec);
        }

     4.重写ListView与ScrollView 兼容:

    protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec)

    Parameters

    • widthMeasureSpec horizontal space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.
    • heightMeasureSpec vertical space requirements as imposed by the parent. The requirements are encoded with View.MeasureSpec.

     重写:

    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
      super.onMeasure(widthMeasureSpec, expandSpec);
     
    }

     ListView

       @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // Sets up mListPadding
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    
            int childWidth = 0;
            int childHeight = 0;
    
            mItemCount = mAdapter == null ? 0 : mAdapter.getCount();
            if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED ||
                    heightMode == MeasureSpec.UNSPECIFIED)) {
                final View child = obtainView(0);
    
                measureScrapChild(child, 0, widthMeasureSpec);
    
                childWidth = child.getMeasuredWidth();
                childHeight = child.getMeasuredHeight();
    
                if (recycleOnMeasure()) {
                    mRecycler.addScrapView(child);
                }
            }
    
            if (widthMode == MeasureSpec.UNSPECIFIED) {
                widthSize = mListPadding.left + mListPadding.right + childWidth +
                        getVerticalScrollbarWidth();
            }
    
            if (heightMode == MeasureSpec.UNSPECIFIED) {
                heightSize = mListPadding.top + mListPadding.bottom + childHeight +
                        getVerticalFadingEdgeLength() * 2;
            }
    
            if (heightMode == MeasureSpec.AT_MOST) {
                // TODO: after first layout we should maybe start at the first visible position, not 0
                heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
            }
    
            setMeasuredDimension(widthSize, heightSize);
            mWidthMeasureSpec = widthMeasureSpec;        
        }
  • 相关阅读:
    百度地图学习
    JS中call和apply区别有哪些 记录
    初次学习AngularJS
    C#中Abstract和Virtua笔记,知识
    css学习笔记四
    css学习笔记三
    jquery基础 笔记三
    jquery基础 笔记二
    jquery基础 笔记一
    负边距在布局中的应用
  • 原文地址:https://www.cnblogs.com/yuyutianxia/p/3735487.html
Copyright © 2011-2022 走看看