Android自定义View的隐藏小彩蛋

很长时间没写! 这次给各位带来一些自定义View中不太让人注意到的原理!

首先,我们先来看一下这个测量模式和参数大小都是对应的:

match_parent—>EXACTLY。怎么理解呢?match_parent就是要利用父View给我们提供的所有剩余空间,而父View剩余空间是确定的,也就是这个测量模式的整数里面存放的尺寸。

wrap_content—>AT_MOST。怎么理解:就是我们想要将大小设置为包裹我们的view内容,那么尺寸大小就是父View给我们作为参考的尺寸,只要不超过这个尺寸就可以啦,具体尺寸就根据我们的需求去设定。

固定尺寸(如100dp)—>EXACTLY。用户自己指定了尺寸大小,我们就不用再去干涉了,当然是以指定的大小为主啦。

那么,接下来就是今天讲解的自定义View中onMeasure(int widthMeasureSpec, int heightMeasureSpec)这个方法。

在一开始学的时候,喜欢看源码的朋友们就会了解到onMeasure方法中的这俩个参数到底是从谁身上传过来的,看完源码就会有这样的一种错觉“这俩个参数是自定义View的父View传进来的”,其实不然;下面开一个简单的事列

这个是布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context=".MainActivity">

    <MyView.MyView
        android:id="@+id/myview"
        android:layout_width="500dp"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>

 

这个是自定义View的onMeasure函数

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthmode = MeasureSpec.getMode(widthMeasureSpec);
        int heightmode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthmode == MeasureSpec.EXACTLY && heightmode == MeasureSpec.AT_MOST) {
            setMeasuredDimension(300,300);
        }
    }

这个是用debug运行过的并且走到了if里面,那么这样说的话父级的宽高参数都是wrap_content,而在Java代码中的判断与我们的所知的onMeasure的参数是父级传过来的就就起了冲突。这个实则也确实不是父级传过来的。

那么问题来了,到底是从谁那里传来的呢,不可能凭空出现吧。是它自己本身传过来的参数吗?我们来验证一下:

还是看上面的代码和布局文件你会看到:自定View的宽是500dp就是这种EXACTLY模式,高是wrap_content就是AT_MOST模式,这样一看,哎,好像真的对上了。大家也可以再多写一些判断条件,我想测试出来的结果也真的是和我一样的。

但是,onMeasure的参数真的是它本身的View传过来的吗?刚刚在上面的实践中也验证过了,确实是这样的。但是如果真是这样的话,我们之前知道的是“子View的测量模式是由父View的测量模式和子View的宽高参数决定的”,那我们现在得出的理论是onMeasure的参数就是子View传过来的和父View没有半毛钱的关系啊!

不要着急看下面这张图:

 

 

把之前的代码和这张图上的内容对比一下:父级View的宽高都是wrap_content模式也都是AT_MOST,子View的宽高模式是EXACTLYAT_MOST 那这样对比的话也确实是父View的测量模式和子View的宽高大小得出新的子View的测量模式

我们有得出一个新的结论

现在有俩种可能:第一种是,我们刚刚测试过的onMeasure的参数是由本身的View传过来的

第二种是,在传参之前,父View的测量模式和iew的宽高大小形成了子View新的测量模式后才传过来的

那么我们就需要在做一些对比了,我们需要得出一个肯定的结论:  看下面

 

布局文件

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context=".MainActivity">

    <MyView.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="300dp" />

</android.support.constraint.ConstraintLayout>

Java代码

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthmode = MeasureSpec.getMode(widthMeasureSpec);
        int heightmode = MeasureSpec.getMode(heightMeasureSpec);
        if (widthmode == MeasureSpec.AT_MOST && heightmode == MeasureSpec.EXACTLY) {
            setMeasuredDimension(300,300);
        }
    }

具体的对比原理就不详细简绍了,我想大家也已经得到了一个最准确的答案了吧。

是的,对比的结果是第二中,之前的对比可能会有异议但是这种的对比就完全消除了第一种可能,所以我们可以肯定的是在传参之前,父View的测量模式和View的宽高大小形成了子View新的测量模式后才传过来的。

 

好了,到这也就结尾了,这里并没有太多的知识,主要是讲解一下onMeasure运行的工作机制。

本篇文章由本人以及百度架构师王家虎共同研发。

https://blog.csdn.net/tuike

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值