我的编程空间,编程开发者的网络收藏夹
学习永远不晚

为什么自定义view的wrap_content会失效

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

为什么自定义view的wrap_content会失效

一、问题描述

在使用自定义View时,View宽 / 高的wrap_content属性不起自身应有的作用,而且是起到与match_parent相同作用。

wrap_content与match_parent区别:

wrap_content:视图的宽/高被设定成刚好适应视图内容的最小尺寸

match_parent:视图的宽/高被设置为充满整个父布局

(在Android API 8之前叫作fill_parent)

其实这里有两个问题:

问题1:wrap_content属性不起自身应有的作用

问题2:wrap_content起到与match_parent相同的作用

二、问题分析

问题出现在View的宽 / 高设置,那我们直接来看自定义View绘制中名列前茅步对View宽 / 高设置的过程:measure过程中的onMeasure()方法

onMeasure()

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  

//参数说明:View的宽 / 高测量规格

//setMeasuredDimension()  用于获得View宽/高的测量值

//这两个参数是通过getDefaultSize()获得的

setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),  

           getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));  

}

继续往下看getDefaultSize()

getDefaultSize()

作用:根据View宽/高的测量规格计算View的宽/高值

源码分析如下:

public static int getDefaultSize(int size, int measureSpec) {  

//参数说明:

// 名列前茅个参数size:提供的默认大小

// 第二个参数:宽/高的测量规格(含模式 & 测量大小)

 //设置默认大小

    int result = size;

    //获取宽/高测量规格的模式 & 测量大小

    int specMode = MeasureSpec.getMode(measureSpec);  

    int specSize = MeasureSpec.getSize(measureSpec);  

    switch (specMode) {  

        // 模式为UNSPECIFIED时,使用提供的默认大小

        // 即名列前茅个参数:size

        case MeasureSpec.UNSPECIFIED:  

            result = size;  

            break;  

        // 模式为AT_MOST,EXACTLY时,使用View测量后的宽/高值

        // 即measureSpec中的specSize

        case MeasureSpec.AT_MOST:  

        case MeasureSpec.EXACTLY:  

            result = specSize;  

            break;  

    }  

 //返回View的宽/高值

    return result;  

}

从上面发现:

在getDefaultSize()的默认实现中,当View的测量模式是AT_MOST或EXACTLY时,View的大小都会被设置成子View MeasureSpec的specSize。

因为AT_MOST对应wrap_content;EXACTLY对应match_parent,所以,默认情况下,wrap_content和match_parent是具有相同的效果的。

解决了问题2:wrap_content起到与match_parent相同的作用

由于在getDefaultSize()的默认实现中,当View被设置成wrap_content和match_parent时,View的大小都会被设置成子View MeasureSpec的specSize。

所以,这个问题的关键在于子View MeasureSpec的specSize的值是多少

我们知道,子View的MeasureSpec值是根据子View的布局参数(LayoutParams)和父容器的MeasureSpec值计算得来,具体计算逻辑封装在getChildMeasureSpec()里。

接下来,看生成子View MeasureSpec的方法:getChildMeasureSpec()的源码分析:

getChildMeasureSpec()

//作用:

/ 根据父视图的MeasureSpec & 布局参数LayoutParams,计算单个子View的MeasureSpec

//即子view的确切大小由两方面共同决定:父view的MeasureSpec 和 子view的LayoutParams属性

public static int getChildMeasureSpec(int spec, int padding, int childDimension) {  

 //参数说明

 * @param spec 父view的详细测量值(MeasureSpec)

 * @param padding view当前尺寸的的内边距和外边距(padding,margin)

 * @param childDimension 子视图的布局参数(宽/高)

    //父view的测量模式

    int specMode = MeasureSpec.getMode(spec);     

    //父view的大小

    int specSize = MeasureSpec.getSize(spec);     

    //通过父view计算出的子view = 父大小-边距(父要求的大小,但子view不一定用这个值)   

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

    //子view想要的实际大小和模式(需要计算)  

    int resultSize = 0;  

    int resultMode = 0;  

    //通过父view的MeasureSpec和子view的LayoutParams确定子view的大小  

    // 当父view的模式为EXACITY时,父view强加给子view确切的值

   //一般是父view设置为match_parent或者固定值的ViewGroup

    switch (specMode) {  

    case MeasureSpec.EXACTLY:  

        // 当子view的LayoutParams>0,即有确切的值  

        if (childDimension >= 0) {  

            //子view大小为子自身所赋的值,模式大小为EXACTLY  

            resultSize = childDimension;  

            resultMode = MeasureSpec.EXACTLY;  

        // 当子view的LayoutParams为MATCH_PARENT时(-1)  

        } else if (childDimension == LayoutParams.MATCH_PARENT) {  

            //子view大小为父view大小,模式为EXACTLY  

            resultSize = size;  

            resultMode = MeasureSpec.EXACTLY;  

        // 当子view的LayoutParams为WRAP_CONTENT时(-2)      

        } else if (childDimension == LayoutParams.WRAP_CONTENT) {  

            //子view决定自己的大小,但最大不能超过父view,模式为AT_MOST  

            resultSize = size;  

            resultMode = MeasureSpec.AT_MOST;  

        }  

        break;  

    // 当父view的模式为AT_MOST时,父view强加给子view一个最大的值。(一般是父view设置为wrap_content)  

    case MeasureSpec.AT_MOST:  

        // 道理同上  

        if (childDimension >= 0) {  

            resultSize = childDimension;  

            resultMode = MeasureSpec.EXACTLY;  

        } else if (childDimension == LayoutParams.MATCH_PARENT) {  

            resultSize = size;  

            resultMode = MeasureSpec.AT_MOST;  

        } else if (childDimension == LayoutParams.WRAP_CONTENT) {  

            resultSize = size;  

            resultMode = MeasureSpec.AT_MOST;  

        }  

        break;  

    // 当父view的模式为UNSPECIFIED时,父容器不对view有任何限制,要多大给多大

    // 多见于ListView、GridView  

    case MeasureSpec.UNSPECIFIED:  

        if (childDimension >= 0) {  

            // 子view大小为子自身所赋的值  

            resultSize = childDimension;  

            resultMode = MeasureSpec.EXACTLY;  

        } else if (childDimension == LayoutParams.MATCH_PARENT) {  

            // 因为父view为UNSPECIFIED,所以MATCH_PARENT的话子类大小为0  

            resultSize = 0;  

            resultMode = MeasureSpec.UNSPECIFIED;  

        } else if (childDimension == LayoutParams.WRAP_CONTENT) {  

            // 因为父view为UNSPECIFIED,所以WRAP_CONTENT的话子类大小为0  

            resultSize = 0;  

            resultMode = MeasureSpec.UNSPECIFIED;  

        }  

        break;  

    }  

    return MeasureSpec.makeMeasureSpec(resultSize, resultMode);  

关于getChildMeasureSpec()里对于子View的测量模式和大小的判断逻辑有点复杂;

三、解决方案

当自定义View的布局参数设置成wrap_content时时,指定一个默认大小(宽 / 高)。

具体是在复写onMeasure()里进行设置

 @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        // 获取宽-测量规则的模式和大小

        Int widthMode = MeasureSpec.getMode(widthMeasureSpec);

        int widthSize = MeasureSpec.getSize(widthMeasureSpec);

        // 获取高-测量规则的模式和大小

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        // 设置wrap_content的默认宽 / 高值

        // 默认宽/高的设定并无固定依据,根据需要灵活设置

        // 类似TextView,ImageView等针对wrap_content均在onMeasure()对设置默认宽 / 高值有特殊处理,具体读者可以自行查看

        int mWidth = 400;

        int mHeight = 400;

      // 当布局参数设置为wrap_content时,设置默认值

        if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT && getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {

            setMeasuredDimension(mWidth, mHeight);

        // 宽 / 高任意一个布局参数为= wrap_content时,都设置默认值

        } else if (getLayoutParams().width == ViewGroup.LayoutParams.WRAP_CONTENT) {

            setMeasuredDimension(mWidth, heightSize);

        } else if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {

            setMeasuredDimension(widthSize, mHeight);

        }

这样,当你的自定义View的宽 / 高设置成wrap_content属性时就会生效了。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

为什么自定义view的wrap_content会失效

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

为什么自定义view的wrap_content会失效

自定义view的wrap_content会失效可以从以下几方面进行分析:一、问题描述;二、问题分析;三、解决方案。在使用自定义View时,View宽 / 高的wrap_content属性不起自身应有的作用,而且是起到与match_parent相同作用。
为什么自定义view的wrap_content会失效
2023-10-29

android自定义view的步骤是什么

自定义Android View的步骤如下:1. 创建一个新的Java类,继承自View或其子类,例如TextView、Button等。2. 在构造函数中进行必要的初始化操作,例如设置属性、加载资源等。3. 重写onMeasure()方法,用
2023-08-15

Android自定义复杂view的方法是什么

要自定义复杂的View,可以按照以下步骤进行:1. 创建一个新的类,继承自View或者ViewGroup的子类,例如LinearLayout、RelativeLayout等。2. 在该类中重写构造方法,通常会有两个构造方法一个是在Java代
2023-09-27

为什么我的自定义错误类型会导致特定模式的错误?

有志者,事竟成!如果你在学习Golang,那么本文《为什么我的自定义错误类型会导致特定模式的错误?》,就很适合你!文章讲解的知识点主要包括,若是你对本文感兴趣,或者是想搞懂其中某个知识点,就请你继续往下看吧~问题内容我正在努力处理 go 的
为什么我的自定义错误类型会导致特定模式的错误?
2024-04-05

Android自定义View实现体重表盘的方法是什么

本篇内容介绍了“Android自定义View实现体重表盘的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!效果视频分析起始角度如下图
2023-06-25

为什么我的 echo jwt 自定义代码不起作用?

php小编鱼仔经常收到读者的问题,其中一个常见的问题是关于"为什么我的 echo jwt 自定义代码不起作用?"。在使用 JWT(JSON Web Token)时,有时候我们会遇到自定义代码不起作用的情况,这可能是因为一些常见的问题导致的。
为什么我的 echo jwt 自定义代码不起作用?
2024-02-08

css怎么实现自定义更为美观的链接提示效果

本篇内容介绍了“css怎么实现自定义更为美观的链接提示效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!建议:尽可能的手写代码,可以有效的提
2023-06-08

为什么我的自定义“超时等待频道”不起作用以及如何使其起作用?

php小编小新在使用自定义“超时等待频道”时,可能会遇到它不起作用的情况。这可能是由于一些常见的问题导致的,例如错误的配置或代码问题。为了使自定义“超时等待频道”起作用,我们可以采取一些解决方法。首先,我们需要确保正确地配置了频道和超时时间
为什么我的自定义“超时等待频道”不起作用以及如何使其起作用?
2024-02-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录