栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Android UI绘制源码解析4(测量规则MeasureSpec解析)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Android UI绘制源码解析4(测量规则MeasureSpec解析)

一 什么是MeasureSpec

我们在上篇文章中已经了解到了UI绘制最终会走到ViewRootImpl的performTraversals()这个方法:

   private void performTraversals() {
		//mWidth:屏幕的宽度      lp.width:DecorView的layoutParam里的宽度模式(match_parent wrap_parent)
	   int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width);
       int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height);   	

	//测量,布局,绘制三个方法入口
  	 performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
   	 performLayout(lp, mWidth, mHeight);
	 performDraw();
}

可以看到,在执行测量的时候,首先会生成childWidthMeasureSpec ,childHeightMeasureSpec 这两个参数,这其实就是DecorView的测量规则,这里解释一下,所谓测量规则,其实就是父View对子View的一种限制,在测量子View的宽度和高度的时候,不能只看我们设置它的本身的大小,还要综合父View给的测量规则综合的得到子View在屏幕上的具体大小;我们知道android的界面顶层的View其实就是DecorView,而我们在加载界面的时候,自然要先得到它的测量规则才能继续测量
我们来看一下getRootMeasureSpec()

  private static int getRootMeasureSpec(int windowSize, int rootDimension) {
        int measureSpec;
        switch (rootDimension) {

        case ViewGroup.LayoutParams.MATCH_PARENT:
            // Window can't resize. Force root view to be windowSize.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
            break;
        case ViewGroup.LayoutParams.WRAP_CONTENT:
            // Window can resize. Set max size for root view.
            measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
            break;
        default:
            // Window wants to be an exact size. Force root view to be that size.
            measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
            break;
        }
        return measureSpec;
    }

这里会根据DecorView的宽高模式来得到具体的MeasureSpec,最终返回一个int类型的值;其实MeasureSpec类似一个工具类,会根据传入的具体参数得到一个int数据类型,里面封装了测量模式和具体的size,接下来我们具体来看一下MeasureSpec这个类。

二 MeasureSpec的源码解析
 public static class MeasureSpec {

        private static final int MODE_SHIFT = 30;
        // 0x3的二进制: 11
        //0x3 << MODE_SHIFT: 11 000000 00000000 00000000 00000000
        private static final int MODE_MASK  = 0x3 << MODE_SHIFT;

        
        @IntDef({UNSPECIFIED, EXACTLY, AT_MOST})
        @Retention(RetentionPolicy.SOURCE)
        public @interface MeasureSpecMode {}

 
        // UNSPECIFIED:00 000000 00000000 00000000 00000000
        public static final int UNSPECIFIED = 0 << MODE_SHIFT; //1

 
        // EXACTLY:01 000000 00000000 00000000 00000000
        public static final int EXACTLY     = 1 << MODE_SHIFT;//2

   
        // AT_MOST:10 000000 00000000 00000000 00000000
        public static final int AT_MOST     = 2 << MODE_SHIFT;//3

  
        public static int makeMeasureSpec(@IntRange(from = 0, to = (1 << MeasureSpec.MODE_SHIFT) - 1) int size,
                                          @MeasureSpecMode int mode) {
            if (sUseBrokenMakeMeasureSpec) {
                return size + mode;
            } else {

                
                return (size & ~MODE_MASK) | (mode & MODE_MASK);

                
            }
        }

MeasureSpec定义了三个变量,代表的是测量模式,就是父View对子View的一个限制

  • UNSPECIFIED:

不确定的,这个在Android开发中很少用

  • EXACTLY :

精确值,子View的大小可以是具体的数值,也可以是match_parent,因为在这个精确模式下,父view的大小是确定的,所以子view直接是等于父view的代销

  • AT_MOST :

子view可以是任意值,但是前提是不能超过父view的大小,对应的子view的大小模式是wrap_parent,所以这个模式也叫最大值模式

可以看到,这三个值都通过了位运算,将对应的二进制位左移到了最左端(int数据类型是32位,也就是32和31位);接着我们来看一下makeMeasureSpec()这个方法,这个方法本质上就是将我们上面说的测量模式和传入的父view大小封装到一个int数据类型的32位二进制中,具体的运算上面写得很清楚了。

OK,现在通过了makeMeasureSpec()这个方法,我们将传入的DecorView的大小和模式封装成一个32位的int数据类型,那么我们又要如何获取size或者测量模式呢,MeasureSpec也提供了两个方法给我们,分别是getMode()和 getSize()

      public static int getMode(int measureSpec) {
            //noinspection ResourceType
            
            return (measureSpec & MODE_MASK);
        }



  public static int getSize(int measureSpec) {

            
            
            return (measureSpec & ~MODE_MASK);
            
        }

很显然,将测量规则和MODE_MASK进行与运算,就得到了测量模式,跟~MODE_MASK进行与运算就得到了大小

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/340589.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号