[Android] 如何计算View的Size

** 注:本文参考链接How Android caculates view size

本文例子如下所示:

<LinearLayout
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="20dp" />

</LinearLayout>

过程

计算view大小的过程可以分为以下几个步骤:
  1. 确定view想要的size(LayoutParams)
  2. 确定parent view的情况(MeasureSpec)
  3. 在parent view的限制下,根据view的LayoutParams,确定view的大小

参数

LayoutParams

LayoutParams用于view表示想要的size的模式。有以下三种:
  1. FILL_PARENT / MATCH_PARENT (-1) view的size和parent view的size一样大
  2. WRAP_CONTENT(-2) view的size仅包裹其内容即可
  3. 指定的值(>0) view的size为指定的size大小

MeasureSpec

MeasureSpec表示当前view的“约束”(在onMeasure中传入)。约束含模式mode和数值size,当前view根据mode来决定如何看待其中的size。

mode

mode有三种,如下所示:
  1. UNSPECIFIED 对当前view的size没有约束
  2. EXACTLY 当前view的bounds(可以理解成“可以使用的范围”)为确定的size,也可以理解成parent view希望当前view(有强制的意味)使用给定的size
  3. AT_MOST 当前view的大小不可超过指定的size
可以利用MeasureSpec的getMode取出具体值.

size

size为8个byte的int值,mode放在前2个bit中。这里可以利用MeasureSpec的getSize取出size的具体值。

onMeasure过程

view通过onMeasure确定自己的大小。确定自己的大小时,需要的东西有:
  1. 约束MeasureSpec
  2. 自己的LayoutParams
  3. 如果有child view,那么需要获取child view的大小
最终确定当前view的size分别为:
  1. measureWidth
  2. measureHeight

single view

以前面例子中的TextView为例,其onMeasure中传入的MeasureSpec为:
  1. Width mode:AT_MOST size:parentContentWidth(LinearLayout的宽-padding)
  2. Height mode:UNSPECIFIED size:不确定
注:这里先不解释为什么MeasureSpec是这样的。 TextView的LayoutParams为:
  1. Width MATCH_PARENT
  2. Height WRAP_CONTENT
然后TextView根据约束和LayoutParams确定自己的大小,包括但不限于以下过程:
  1. 设置宽度为parentContentWidth,考虑margin确定字符可用范围
  2. 根据字符高度和字体设置(根据是否超过parentContentWidth确定是否换行)等计算字符所占的高度(没有限制)。
  3. 设置measureWidth和measureHeight

ViewGroup

以前面例子中的LinearLayout为例,假设该LinearLayout为Activity中的root layout其onMeasure中传入的MeasureSpec为:
  1. Width mode:EXACTLY size:parentContentWidth(LinearLayout的parent view的宽-padding)
  2. Height mode:AT_MOST size:parentContentHeight(LinearLayout的parent view的高-padding)
RelativeLayout的LayoutParams为:
  1. Width MATCH_PARENT
  2. Height WRAP_CONTENT
  3. Orientation vertical
然后LinearLayout根据约束和LayoutParams确定自己的大小,包括但不限于以下过程:
  1. 确定child view的排列方式
  2. 确定TextView的size
  3. 确定ImageView的size
  4. 根据自身的设置,设置measureWidth和measureHeight
要确定child view的size,就要调用child view的onMeasure,传入合适的MeasureSpec,表明parent view对child的约束。 根据parent view的不同module和child view的不同LayoutParams,有如下规则:
  1. 当parent view的mode是EXACTLY时:
child layoutmodesize
exact sizeEXACTLYchildSizeChild wants a specific size.
MATCH_PARENTEXACTLYparentContentSizeChild wants to be parent's size.
WRAP_CONTENTAT_MOSTparentContentSizeChild wants to determine its own size. It can not be bigger than parent.
  1. 当parent view的mode是AT_MOST时:
child layoutmodesize
exact sizeEXACTLYchildSizeChild wants a specific size
MATCH_PARENTAT_MOSTparentContentSizeChild wants to be parent's size, but parent's size is not fixed. Constrain child to not be bigger than parent.
WRAP_CONTENTAT_MOSTparentContentSizeChild wants to determine its own size, but it can not be bigger than parent.
  1. 当parent view的mode是UNSPECIFIED时:
child layoutmodesize
exact sizeEXACTLYchildSizeChild wants a specific size.
MATCH_PARENTUNSPECIFIEDcan not decide yetChild wants to be parent's size. Child will decide its own size later.
WRAP_CONTENTUNSPECIFIEDcan not decide yetChild wants to be its own size. Child will decide its own size later.
以例子中的TextView为例:
  1. LinearLayout的width mode为EXACTLY,TextView的width layout param为MATCH_PARENT
  2. LinearLayout的height mode为AT_MOST,TextView的height layout param为WRAP_CONTENT
所以TextView的onMeasure会被传入:
  1. Width mode:EXACTLY size:parentContentWidth(LinearLayout的宽-padding)
  2. Height mode:AT_MOST size:parentContentHeight(LinearLayout的高-padding)
TextView可以根据上述约束计算自己的大小。ImageView同理。最后LinearLayout根据ImageView和TextView的大小计算自己的大小。注意这里没有weight的设置,所以onMeasure只运行一次。 如上述有错,请留言告知。

查看原文:http://legendmohe.net/2018/01/31/android-%e5%a6%82%e4%bd%95%e8%ae%a1%e7%ae%97view%e7%9a%84size/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值