`
daojin
  • 浏览: 696288 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

安卓高手之路 图形系统(4 Measure的算法)

 
阅读更多

 	    


 /**
     * 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 = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            } else if (childDimension == LayoutParams.WRAP_CONTENT) {
                // Child wants to determine its own size.... find out how
                // big it should be
                resultSize = 0;
                resultMode = MeasureSpec.UNSPECIFIED;
            }
            break;
        }
        return MeasureSpec.makeMeasureSpec(resultSize, resultMode);
    }

 这个Measure算法主要是算child的测量方式和大小的。主要根据两种根据:

1. 自身的测量方式(MeasureSpec EXACTLY,AT_MOST,UNSPECIFIED)【这个是parent传过来的】
2. 自身的大小 【这个是parent传过来的】
3. 自己的padding【计算得到】
4. child的大小【child的LayoutParam得到】

根据以上四个推测出child的MeasureSpec 。也就是大小和测量方式。

child的请求大小来确定到底child应该有多宽以及应该怎么测量。

下面的逻辑比较多。

1.如果当前View是Exactly。那么也就是说有了固定的大小。
  
  那么Child如果说是一个固定的LayoutParam.width 或者 height,那么返回结果resultSize 就设置为这个固定值。
 
 
 
 

如果child是wrapContent,那么resultSize 就设置为当前这个View的工作区大小。也就是去除pad和margin
  的大小。同时,测量方式设置为AT_MOST

如果child是match_parent,那么由于当前View是固定大小的。那么resultSize 就设置为当前这个View的工作区大小。也就是去除pad和margin
  的大小。同时,测量方式设置为EXACTLY

2.如果当前View是MeasureSpec.AT_MOST。也就是说有个最大值。也是这三种情况
  a.fixed
     这个时候,当前View可以无限大,并且child有个固定值。那么就设置这个值吧。   这个地方
,没有做越界判断,因此有时候会出现一个子View非常大,撑破了父View的情况。google在这里
算不算是一个bug呢?也就是当前的currrentView为wrap_content.但是parentView却有一个fixed value。 同时,childView也有一个fixed Value。这个时候,如果childView的大小超过了parentView。 则会出现childView显示不全的现象。
  b.wrap_content
    
     同理,传入AT_MOST.但是不超过当前View的大小。【这个是与当前View为EXACTLY的情况一样】
    
  c.fill_parent

       这种情况也非常奇怪。发生在
currentView是wrap_content.而childView是fill_parent的情况。这个时候就没办法搞了。
这个时候,就告诉子View你也没有固定的大小。也就是说循环依赖产生了。唯一的办法是让childView 继续wrap_content.也就是废掉这个fill_parent。从而打破了这种循环依赖。

分享到:
评论

相关推荐

    一键切图工具

    这类工具背后的实现往往涉及到图像处理算法、自动化脚本(如JavaScript或Python)、以及图形用户界面设计。它们通常有跨平台的特性,可以运行在Windows、Mac OS或Linux系统上。 6. 常见的一键切图工具: - Sketch...

    波浪滚动圆球View

    在Android开发中,自定义View是一项常见的需求,用于实现独特的用户界面效果,增强用户体验。"波浪滚动圆球View"就是一个这样的自定义组件,它模仿了魅族、华为等品牌设备上的滚动效果,通过波浪式的动画使得圆球在...

    ruler tools

    描述中的“user to measure object size”进一步明确了这个工具是为用户提供测量物体大小的能力。在计算机上,这可能通过交互式的图形用户界面实现,让用户能够点击或拖动来确定物体的长度、宽度或其他尺寸。 从...

    circletextview-源码.rar

    总结来说,CircletextView的源码分析涵盖了Android自定义视图的基本原理,包括文字测量、视图尺寸计算、图形绘制和性能优化。通过深入理解这些概念,开发者不仅可以使用CircletextView库,还能以此为基础创建更多...

    CellularLayout:第一次提交

    1. **自定义布局容器**:在JavaFX或Android中,需要自定义一个布局容器类,继承自`javafx.scene.layout.Region`或`android.view.ViewGroup`,然后重写相关的测量、布局和绘制方法,如`measure()`, `layout()`, 和 `...

Global site tag (gtag.js) - Google Analytics