match_parent、wrap_parent、具体值 和 MeasureSpec 类中 mode 的对应关系
来源:互联网 发布:dwg mac 编辑:程序博客网 时间:2024/05/21 10:33
如果不考虑父 view 的影响,测试结果如下:
* wrap_parent -> MeasureSpec.AT_MOST
* match_parent -> MeasureSpec.EXACTLY
* 具体值 -> MeasureSpec.EXACTLY
这是一个符合我们直觉的结果。
一个 view 的 onMeasure 方法最终得到的测量规格值(测量约束值)中包含的测量模式和上面不一定对的上,这是因为 onMeasure 方法中得到的测量规格值(测量约束值)是 measure 方法传过来的,父 view 在调用 measure 方法的时候可以根据自己的情况不使用 ViewGroup 提供的 measureChildren 方法,而改变上面的映射关系,比如 RelativeLayout 中就结合其他 Layout 属性综合确定 MeasureSpec 中的模式。上面的映射关系可以直接查看 ViewGroup 类的 getChildMeasureSpec 方法,这是最简单的 measure 子 view 的方式.
ViewGroup 中 measureChild 方法如下:
protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { final LayoutParams lp = child.getLayoutParams(); final int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingLeft + mPaddingRight, lp.width); final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, mPaddingTop + mPaddingBottom, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); }
getChildMeasureSpec 方法如下:
public static int getChildMeasureSpec(int spec, int padding, int childDimension) { int specMode = MeasureSpec.getMode(spec); int specSize = MeasureSpec.getSize(spec); int size = Math.max(0, specSize - padding); int resultSize = 0; int resultMode = 0; switch (specMode) { // Parent has imposed an exact size on us case MeasureSpec.EXACTLY: if (childDimension >= 0) { resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size. So be it. resultSize = size; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent has imposed a maximum size on us case MeasureSpec.AT_MOST: if (childDimension >= 0) { // Child wants a specific size... so be it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size, but our size is not fixed. // Constrain child to not be bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size. It can't be // bigger than us. resultSize = size; resultMode = MeasureSpec.AT_MOST; } break; // Parent asked to see how big we want to be case MeasureSpec.UNSPECIFIED: if (childDimension >= 0) { // Child wants a specific size... let him have it resultSize = childDimension; resultMode = MeasureSpec.EXACTLY; } else if (childDimension == LayoutParams.MATCH_PARENT) { // Child wants to be our size... find out how big it should // be resultSize = 0; resultMode = MeasureSpec.UNSPECIFIED; } else if (childDimension == LayoutParams.WRAP_CONTENT) { // Child wants to determine its own size.... find out how // big it should be resultSize = 0; resultMode = MeasureSpec.UNSPECIFIED; } break; } return MeasureSpec.makeMeasureSpec(resultSize, resultMode); }我们父 view 是 match_parent 情况下我们只需要关注 case MeasureSpec.EXACTLY 就行了。view 自带的 geDefaultSize 这个方法如果设置包裹内容,最后得到的 view 不会是包裹内容,而是父 view 指定的大小。正如 geDefaultSize 这个方法中 switch 代码中所展示的逻辑。所以 getDefaultSize 这个方法还是很粗糙的方法,连 wrap_content 这个属性都没有提供支持,当然对 match_parent 和 指定值 还是有支持的。这也就是说 View 中自带的 onMeasure 其实可以用性很低。也难怪 reference 文档中说 子 view 必须重新 onMeasure。ViewGroup 中的 measureChildren 方法没有对 margin 进行处理,所以如果子 view 的属性带 margin,那么他其实是不能给子 view 一个结合 margin 的测量约束值。
测试代码如下
TestView.java
/** * 测试 match_parent、wrap_parent、具体值 和 MeasureSpec 中 mode 的对应关系 */package com.example.testmeasurespec;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.View;public class TestView extends View { private static final String TAG = "TestView"; public TestView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public TestView(Context context, AttributeSet attrs) { super(context, attrs); } public TestView(Context context) { super(context); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { Log.i(TAG, "onMeasure:" + getTag()); setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); } public static int getDefaultSize(int size, int measureSpec) { int result = size; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); switch (specMode) { case MeasureSpec.UNSPECIFIED: Log.i(TAG, "specMode:MeasureSpec.UNSPECIFIED"); result = size; break; case MeasureSpec.AT_MOST: Log.i(TAG, "specMode:MeasureSpec.AT_MOST"); case MeasureSpec.EXACTLY: Log.i(TAG, "specMode:MeasureSpec.EXACTLY"); result = specSize; break; } return result; }}
TestLayout.java
public class TestLayout extends ViewGroup { public TestLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public TestLayout(Context context, AttributeSet attrs) { super(context, attrs); } public TestLayout(Context context) { super(context); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { measureChildren(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); }}
main_activity.xml
<com.example.testmeasurespec.TestLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.testmeasurespec.TestView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_launcher" android:tag="test1" /> <com.example.testmeasurespec.TestView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/ic_launcher" android:tag="test2" /> <com.example.testmeasurespec.TestView android:layout_width="20dp" android:layout_height="20dp" android:background="@drawable/ic_launcher" android:tag="test3" /></com.example.testmeasurespec.TestLayout>
1 0
- match_parent、wrap_parent、具体值 和 MeasureSpec 类中 mode 的对应关系
- android中fill_parent,match_parent,wrap_parent的区别
- match_parent fill_parent和wrap_parent的区别
- match_Parent、fill_parent和wrap_Parent区别
- 源码分析:LayoutParams的wrap_content, match_parent, 和具体值
- 源码分析:LayoutParams的wrap_content, match_parent, 和具体值
- Android之wrap_parent,match_parent,fill_parent的区别与联系
- [看书日记20151226]MeasureSpec和LayoutParams的对应关系 , View的工作流程
- 继承关系树的每个具体类对应一张表
- 自定义view的measureSpec是谁的mode和size
- word2007中字号、磅值和毫米的对应关系
- Android中fill_parent和match_parent的区别?
- View MeasureSpec 和LayoutParams关系
- Android中Signature和Java中Certificate的对应关系
- Jni中C++和Java的数据类型的对应关系
- Jni中C++和Java的数据类型的对应关系
- Jni中C++和Java的数据类型的对应关系
- SQL Server中ASCII和字符对应关系的方法
- iOS 本地音频播放AVAudioPlayer
- 非模态对话框销毁的问题,SldWorks二次开发的朋友可以看看
- c# IDL混编部署
- Codeforces #276 div.1 E
- Spring对Orace数据库进行的建表,建序列、建引擎、增、删、查、改:
- match_parent、wrap_parent、具体值 和 MeasureSpec 类中 mode 的对应关系
- POJ 3254 Corn Fields
- Linux服务器上监控网络带宽的18个常用命令
- 写给大二女生:发现问题,主动想办法解决
- C++全局变量的声明和定义
- 键盘弹起与隐藏时高度的获取及动画 适配所有iOS系统
- mongdb性能优化收集
- 【HDU】3886 Final Kichiku “Lanlanshu” 数位DP
- Ubuntu install ia32-libs