我是靠谱客的博主 霸气糖豆,这篇文章主要介绍measure之UNSPECIFIED的用途measure之UNSPECIFIED的用途,现在分享给大家,希望可以做个参考。

measure之UNSPECIFIED的用途

  • measure之UNSPECIFIED的用途
    • 一. 前言
    • 二. demo代码
    • 三. 截图
    • 四. 源码分析
      • 4.1 先看ScrollView的measure源码:
      • 4.2 再来看TextView源码
    • 五. 总结

一. 前言

对于MeasureSpec很多人很陌生,而对于MeasureSpec.UNSPECIFIED就更陌生了,在这篇文章里讲UNSPECIFIED,因为很多人对它很陌生,本人通过一个demo场景,并跟踪代码,来坦述UNSPECIFIED的用途

二. demo代码

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?> <ScrollView 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="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <TextView android:layout_width="match_parent" android:layout_height="300dp" android:background="@color/gray" android:hint="haha" /> </ScrollView>
复制代码
1
2
3
4
5
6
7
8
9
10
11
import android.app.Activity; import android.os.Bundle; import android.support.annotation.Nullable; public class ScrollViewEditTextActivity extends Activity { @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.scroll_view_edit_text); } }

三. 截图

事情并不是你想像的那样,为什么我给定高度不好使,TextView的高度为什么只有一行的高度
截图

四. 源码分析

4.1 先看ScrollView的measure源码:

ScrollView.java

复制代码
1
2
3
4
5
6
7
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (!mFillViewport) { return; } //...ignore code

这里mFillViewport为false,也就是说它走的是super.onMeasure,super是FrameLayout

FrameLayout.java

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int count = getChildCount(); //...ignore code int maxHeight = 0; int maxWidth = 0; int childState = 0; for (int i = 0; i < count; i++) { final View child = getChildAt(i); if (mMeasureAllChildren || child.getVisibility() != GONE) { measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0); //...ignore code

遍历子view,然后调用measureChildWithMargins,而这个方法被ScrllView覆盖了

ScrollView.java

复制代码
1
2
3
4
5
6
7
8
9
10
11
@Override protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin + widthUsed, lp.width); final int childHeightMeasureSpec = MeasureSpec.makeSafeMeasureSpec( MeasureSpec.getSize(parentHeightMeasureSpec), MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }

这里重点看第10行,它强行把size和mode=MeasureSpec.UNSPECIFIED传给子View

makeSafeMeasureSpec原理可以参考 MeasureSpec存储信息

4.2 再来看TextView源码

而TextView的Measure

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //...ignore code if (heightMode == MeasureSpec.EXACTLY) { // Parent has told us how big to be. So be it. height = heightSize; mDesiredHeightAtMeasure = -1; } else { int desired = getDesiredHeight(); height = desired; mDesiredHeightAtMeasure = desired; if (heightMode == MeasureSpec.AT_MOST) { height = Math.min(desired, heightSize); } } int unpaddedHeight = height - getCompoundPaddingTop() - getCompoundPaddingBottom(); if (mMaxMode == LINES && mLayout.getLineCount() > mMaximum) { unpaddedHeight = Math.min(unpaddedHeight, mLayout.getLineTop(mMaximum)); } /* * We didn't let makeNewLayout() register to bring the cursor into view, * so do it here if there is any possibility that it is needed. */ if (mMovement != null || mLayout.getWidth() > unpaddedWidth || mLayout.getHeight() > unpaddedHeight) { registerForPreDraw(); } else { scrollTo(0, 0); } setMeasuredDimension(width, height); }
  1. 如果父容器是ScrollView,那mode=UNSPECIFIED,就会走第8行
  2. 第9行是根据内容算出行数再确定高度,也就是TextView的实际内容高度
  3. 然后这个高度就传给了setMeasuredDimension
  4. 导致xml里配的高度不生效,这也是有些程序员会说我设了高度为啥没生效的原因
  5. 抛开ScrollView不说,如果父容器是atMost,它会根据父容器能支持的最大高度和desired对比,取最小的;因此at_most就是wrap_content,至于为什么at_most对应的是wrap_content,有兴趣可以看源码。

五. 总结

  1. UNSPECIFIED会在ScrollView的measure方法里传给子View
  2. 子View收到UNSPECIFIED,会根据自己的实际内容大小来决定高度
  3. UNSPECIFIED与AT_MOST的区别就是,它没有最大size限定这也说明UNSPECIFIED在ScrollView里很实用,因为ScrllView不需要限定子View的大小,它可以滚动嘛

最后

以上就是霸气糖豆最近收集整理的关于measure之UNSPECIFIED的用途measure之UNSPECIFIED的用途的全部内容,更多相关measure之UNSPECIFIED内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

评论列表共有 0 条评论

立即
投稿
返回
顶部