美文网首页
【Android】自定义View为什么要处理wrap_conte

【Android】自定义View为什么要处理wrap_conte

作者: 小城哇哇 | 来源:发表于2023-02-22 15:00 被阅读0次

自定义View中,如果View宽或者高设置wrap_content而我们不做任何处理,最终的效果是和match_parent相同的,本文主要是从源码的角度讲解下为什么会发生这种情况

1.自定义View假如不处理wrap_content

随便自定义一个View:

class CustomView @JvmOverloads constructor(
    context: Context,
    attributes: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attributes, defStyleAttr) {
} 

我们在xml中分别设置math_parentwrap_content看下效果:

<com.example.gitlinux.CustomView
    android:background="#00ff00"
    android:layout_width="match_parent"
    android:layout_height="100dp"/>

<com.example.gitlinux.CustomView
    android:background="#ff0000"
    android:layout_width="wrap_content"
    android:layout_height="100dp"/> 

分别对应:

image.png

可以看到,CustomView的宽度设置math_parentwrap_content结果相同,这是为什么呢,接下来让我们从源码中寻找答案

2.View测量规格

在看源码之前,我们先了解下View的测量规格MeasureSpec:高2位代表Mode,低30位代表Size
MeasureSpec分为三种测量mode:

  • AT_MOST 父View当前剩余分配空间,大小就是Size,子View的大小不能超过Size,对应LayoutParams中的wrap_content模式
  • EXACTLY 父View检测出的子View的最终大小就是Size,对应LayoutParams中的match_parent、具体数值 两种模式
  • UNSPECIFIED 父View对view不限制,要多大给多大,比较少使用,这个可以用来获取View真实的宽高,比如ScrollView高度上就指定了这种测量模式

3.源码寻找为什么math_parentwrap_content结果相同:

首先我们先有个确定的概念:View最终的宽高MeasureSpec是由父View的MeasureSpec和子View的LayoutParam来决定的。

我们以ViewGroupmeasureChildWithMargins()方法作为切入口

image.png 首先获取子View的LayoutParam,调用了getChildMeasureSpec()方法传入了子View的LayoutParam和父View的宽高的MeasureSpec

getChildMeasureSpec()方法比较长,我们主要截取下其中的关键逻辑:

image.png image.png
当父View的测试模式为EXACTLY时,子View的LayoutParam如果为具体数值和match_parent,则子View的MeasureSpec测量规格就为EXACTLY,否则为AT_MOST image.png
当父View的测试模式为AT_MOST时,子View的LayoutParam如果为wrap_contentmatch_parent,则子View的MeasureSpec测量规格就为AT_MOST,否则为EXACTLY

我们用一个表格直观的看下子View的MeasureSpec生成过程:

image

现在我们回到文章最开始的那个问题 :如果自定义View的宽度设置为wrap_content,从上面的表格中可以看出不管父View的测量规格是AT_MOST还是EXACTLY,子View最终的宽度大小都是和宽度设置为match_parent时的大小相同。

最终是怎么设置成子View的宽高大小的呢,具体的源码就不带着分析了,大体的调用逻辑就是:

通过刚才measureChildWithMargins()方法,在获取到子View宽和高的MeasureSpec之后,就调用了子View的measure()->onMeasure()->setMeasuredDimension()->setMeasuredDimensionRaw()方法,最终完成子View宽高大小设置

3.如何解决math_parentwrap_content结果相同

这个就得要求自定义View时,需要重写View的onMeasure()方法,在这个方法中判断当前View的宽或者高的布局参数是否为wrap_content,如果是就得手动计算所需真实的宽高,然后调用setMeasuredDimension()设置

相关文章

网友评论

      本文标题:【Android】自定义View为什么要处理wrap_conte

      本文链接:https://www.haomeiwen.com/subject/wtiikdtx.html