我是靠谱客的博主 霸气糖豆,最近开发中收集的这篇文章主要介绍measure之UNSPECIFIED的用途measure之UNSPECIFIED的用途,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

measure之UNSPECIFIED的用途

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

一. 前言

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

二. demo代码

<?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>
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

@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


@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

@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

@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的用途measure之UNSPECIFIED的用途所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部