android自定义view系列-measurespec(代码片段)

Q-CODER Q-CODER     2022-11-09     793

关键词:

【Android】自定义 View 系列- 绘制流程 一文中,在测量过程中,是通过 一定的规则 得出最后我们测量的宽高,然后通过 setMeasuredDimension() 保存结果。

那么这里说到的规则主要就是---MeasureSpec 和 LayoutParams

MeasureSpec 是??

//源码描述
/**
* 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.MeasureSpec 父 View 对子 View 的宽高要求。
2.MeasureSpec 包含了两个信息 模式(mode)和大小(size)
3.一共有三种模式:
    UNSPECIFIED- 任意大小(It can be whatever size it wants )-例如 recyclerview 子View 的大小是超过父View 的大小的
    EXACTLY - 精确值(regardless of how big is wants to be, an exact size )、
    AT_MOST - 在父View 的限制范围中任意大小(as large as it wants up to the specified size).

但是,对于我们开发者来说,我们知道一个 View 的大小,不是应该由我们通过 layout_width 和 layout_height 决定的吗?

对,也不对。事实是,在对于任意一个View (包括ViewGroup),最终的大小是由父 View 的要求(MeasureSpec)和子View 自己的需求(LayoutParams-layout_width & layout_height)决定的。具体是如何决定的呢?

/**
* @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 them 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;
    
    //noinspection ResourceType
    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);

(上面代码逻辑很简单,源码的注解也很贴心了,请各位耐心读完。然后再看下面的总结表格,切忌死记硬背下面的表格)

总结为表格,其中:childDimension(子View 自身大小)、size(父view剩余空间)

EXACTLY

AT_MOST

UNSPECIFIED

具体值

(即 childDimension ≥ 0)

模式:EXACTLY

大小:childDimension

模式:EXACTLY

大小:childDimension

模式:EXACTLY

大小:childDimension

match_parent

模式:EXACTLY

大小:size

模式:AT_MOST

大小:size

模式:UNSPECIFIED

大小:View.sUseZeroUnspecifiedMeasureSpec ? 0 : size

wrap_content

模式:AT_MOST

大小:size

模式:AT_MOST

大小:size

模式:UNSPECIFIED

大小:View.sUseZeroUnspecifiedMeasureSpec ? 0 : size


今日疑问:为什么在一次事件序列中 onInterceptTouchEvent() 返回 true 后就不会再次执行onInterceptTouchEvent() 了,而在下一次事件序列中又会再次触发吗?

这个问题,我暂时没有找到切确的答案。截止目前研究,暂时认为是 mGroupFlags 标志被改变后,导致进入 onInterceptTouchEvent() 不再触发,并且在 UP/CANCEL/HOVER_MOVE 和下次事件序列开始(即 DOWN) 会调用 resetTouchState() 重置状态。这样又可以触onInterceptTouchEvent()。

对于 MeasureSpec 的内容和 上述疑问欢迎大家评论区交流~

攻克android软键盘的疑难杂症

系列教程:推翻自己和过往,重学自定义View自定义View系列教程01–常用工具介绍自定义View系列教程02–onMeasure源码详尽分析自定义View系列教程03–onLayout源码详尽分析自定义View系列教程04–Draw源码分析及其实践自定义View系列教... 查看详情

android自定义view详解(代码片段)

View的绘制系列文章:AndroidView绘制流程之DecorView与ViewRootImplAndroidView的绘制流程之Measure过程详解(一)AndroidView的绘制流程之Layout和Draw过程详解(二)AndroidView的事件分发原理解析对于Android开发者来说,原生控件往往无法满足要求,... 查看详情

android自定义的dialog怎么设置view

自定义的dialog例子很多,通过measure方法进行绘制参考技术AViewview=LayoutInflater.from(this).inflate(resource,null);dialog.setView(view); 查看详情

android自定义view系列实战篇-view(代码片段)

QRatingViewAcustomviewforratingwhicheasytomakeanduse,butfunctionisexcellent.github-QRatingViewEffectPictureProperties<declare-styleablename="QRatingView"><!--未选中图片--><attrna 查看详情

android自定义view系列-measurespec(代码片段)

在【Android】自定义View系列-绘制流程一文中,在测量过程中,是通过一定的规则得出最后我们测量的宽高,然后通过setMeasuredDimension()保存结果。那么这里说到的规则主要就是---MeasureSpec和LayoutParamsMeasureSpec是?ÿ... 查看详情

自定义view系列一自定义view的构造函数,自定义属性(代码片段)

...列一自定义View的构造函数,自定义属性引:自定义View对于Android开发者是一道坎.虽然说是坎但是也得走过去的!此系列文章作为学习自定义View的一系列学习笔记.在进入学习自定义View的殿堂, 查看详情

128view绘制流程&自定义view

记清楚函数调用的顺序才能准确地进行调用。根据调用链,可将整个绘制过程分为三部分:Measure-Layout-DrawMeasure过程1.测量过程由上至下,在measure过程的最后,每个视图将存储自己的尺寸大小和测量规格。2.measure过程会为一个View... 查看详情

自定义view基础-最易懂的自定义view原理系列

前言自定义View原理是Android开发者必须了解的基础;在了解自定义View之前,你需要有一定的知识储备;本文将全面解析关于自定义View中的所有知识基础。目录1.View的分类视图View主要分为两类:类别解释特点单一视图即一个View,... 查看详情

android自定义view系列-measurespec(代码片段)

在【Android】自定义View系列-绘制流程一文中,在测量过程中,是通过一定的规则得出最后我们测量的宽高,然后通过setMeasuredDimension()保存结果。那么这里说到的规则主要就是---MeasureSpec和LayoutParamsMeasureSpec是?ÿ... 查看详情

android自定义view系列-measurespec(代码片段)

在【Android】自定义View系列-绘制流程一文中,在测量过程中,是通过一定的规则得出最后我们测量的宽高,然后通过setMeasuredDimension()保存结果。那么这里说到的规则主要就是---MeasureSpec和LayoutParamsMeasureSpec是?ÿ... 查看详情

android自定义view系列实战篇-viewgroup(代码片段)

...详尽地写在代码中。先上效果图兄弟们,上代码importandroid.content.Cont 查看详情

android自定义view系列-view(代码片段)

QRatingViewAcustomviewforratingwhicheasytomakeanduse,butfunctionisexcellent.github-QRatingViewEffectPictureProperties<declare-styleablename="QRatingView"><!--未选中图片--><attrname="normalIcon"format="reference"/><!--选中图片--><... 查看详情

android自定义view系列实战篇-view(代码片段)

QRatingViewAcustomviewforratingwhicheasytomakeanduse,butfunctionisexcellent.github-QRatingViewEffectPictureProperties<declare-styleablename="QRatingView"><!--未选中图片--><attrname="normalIcon"format="reference"/><!--选中图片--><... 查看详情

android进阶知识——view的工作原理(代码片段)

文章目录1.初识ViewRoot和DecorView2.理解MeasureSpec2.1MeasureSpec2.2MeasureSpec和LayoutParams的对应关系4.View的工作流程3.1measure过程3.2layout过程3.3draw过程4.自定义View4.1自定义View的分类4.2自定义View须知4.3自定义View示例本章我们主要介绍两个方... 查看详情

android自定义view之自定义一个简单的阶梯式布局(代码片段)

onMeasure:确定自身的大小确定子View的大小流程:1.ViewGroup开始测量自己的尺寸2.为每个子View计算测量的限制信息3.把上一步确定的限制信息,传递给每一个字View,然后子View开始measure自己的尺寸4.获取子View测量完... 查看详情

android群英传笔记系列三view的自定义:实现一个模拟下载

1.实现效果:动态显示进度(分别显示了整个的动态改变的过程,然后完成后,弹出一个对话框)     2.实现过程:可以分为绘制一个圆,圆弧和文本三部分,然后在MainAcitivity中通过线程模拟下载进度。a.定义... 查看详情

android自定义view系列-viewgroup(代码片段)

...尽地写在代码中。先上效果图  兄弟们,上代码importandroid.content.Contextimportandroid.graphics.Rectimportandroid.util.AttributeSetimportandroid.view.ViewGroupimportandroidx.core.view.childrenimportkotlin.math.max/****@Author:QCoder*@CreateDate:2021/12/6*@Descrip... 查看详情

讲讲android为自定义view提供的surfaceview(代码片段)

系列文章目录讲讲Android为自定义view提供的SurfaceView文章目录系列文章目录前言一、Android为什么会提供SurfaceView二、先看看AndroidDemo的实现1.实现接口以及接口定义的方法2.与Activity生命周期进行绑定3.完成初始化操作4.实现5.运行三... 查看详情