源代码分析:LayoutParams的wrap_content, match_parent, 而详细的价值观
问题:
慢慢地熟悉android 的过程中。发现view 要么layout初始化,建或者生产活动是很清楚。被添加到父控制,然后开始了相应的生命周期。但父控件的整个界面。还是第一个系统view。 怎么来的,如何初始化和绘制?
概述:
带着困扰我的问题,本文试图分析理解view 的measure 的过程,在分析过程中重点分析了LayoutParams 中MATCH_PARENT和MATCH_PARENT 的相应关系。onMeasure 默认值的计算过程;解释了onMeasure 接口中的凝视中的问题,并提出一个问题:ViewRootImpl 是怎么创建的? 留作下篇引子。
最后。讨论怎样重写onMeasure()方法。
LayoutParams 中MATCH_PARENT和MATCH_PARENT 的相应关系
为什么从perform 開始本文。请见Android 动画animation 深入分析
在android.view.ViewRootImpl.performTraversals() 中開始measure的过程
childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width);
childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height);
host.measure(childWidthMeasureSpec, childHeightMeasureSpec);
在android.view.ViewRootImpl 中能够看到其相应关系LayoutParams 中这三个值在内部有个相应关系。那就是
LayoutParams.MATCH_PARENT 相应 MeasureSpec.EXACTLY
.LayoutParams.WRAP_CONTENT相应 MeasureSpec.AT_MOST
默认值(也就是详细值) 相应 MeasureSpec.EXACTLY
也就是内部仅仅有两种模式 EXACTLY 精确模式 和 AT_MOST 最大模式。
private int getRootMeasureSpec(int windowSize, int rootDimension) {
int measureSpec;
switch (rootDimension) { case ViewGroup.LayoutParams.MATCH_PARENT:
// Window can't resize. Force root view to be windowSize.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.EXACTLY);
break;
case ViewGroup.LayoutParams.WRAP_CONTENT:
// Window can resize. Set max size for root view.
measureSpec = MeasureSpec.makeMeasureSpec(windowSize, MeasureSpec.AT_MOST);
break;
default:
// Window wants to be an exact size. Force root view to be that size.
measureSpec = MeasureSpec.makeMeasureSpec(rootDimension, MeasureSpec.EXACTLY);
break;
}
return measureSpec;
}
在这个getRootMeasureSpe() 中调用了makeMeasureSpec() 这个函数,从实现来看,通过按位与 的方法。把模式值和 详细的大小合并成了一个值。由于屏幕尺寸大小眼下远小于30位, 就用了最高两位来标识计算的模式。
private static final int MODE_SHIFT = 30;
public static final int EXACTLY = 1 << MODE_SHIFT;
public static final int AT_MOST = 2 << MODE_SHIFT;
public static int makeMeasureSpec(int size, int mode) {
return size + mode;
}
得到了宽、高的measureSpec 后,调用View.measure()。 能够看到measure的过程就是调用了 view 的onMeasure()方法。 就是假设要自己定义view的话须要重写的onMeasure()方法。
public final void measure(int widthMeasureSpec, int heightMeasureSpec) {
if ((mPrivateFlags & FORCE_LAYOUT) == FORCE_LAYOUT ||
widthMeasureSpec != mOldWidthMeasureSpec ||
heightMeasureSpec != mOldHeightMeasureSpec) { // measure ourselves, this should set the measured dimension flag back
onMeasure(widthMeasureSpec, heightMeasureSpec);
} mOldWidthMeasureSpec = widthMeasureSpec;
mOldHeightMeasureSpec = heightMeasureSpec;
}
从onMeasure的凝视中能够看到:
1. onMeasure() 方法是被用来计算宽高的, 子类须要重写这种方法来提供更加准确和高效的计算方法。
2. 假设重写这种方法的话,必须调用setMeasuredDimension(int, int) 来保存计算的宽高的结果。否则会抛出异常IllegalStateException;
3. 基类的实现默认是使用背景大小来计算宽高,
4. 假设重写这种方法。 应该确保计算宽高的结果应该不小于view 的最小的宽高, ({@link #getSuggestedMinimumHeight()} and * {@link #getSuggestedMinimumWidth()})
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec),
getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec));
}
onMeasure 默认值的计算过程
这里看一下默认值是怎么计算的,然后再讨论一下自己定义的onMeasure()应该怎么写。
1 首先。得到建议的最小高度, getSuggestedMinimumWidth(),果然如凝视所写。 在背景不为空的情况下,使用背景的最小宽高。这里的mMinWidth 是layout 属性中的minWidth 或者minHeight。 假设没有写,默认值为零。由此可见在layout过程中写的最小值在默认情况下的确能够保证view的最小大小。
思考一下,为什么没有提供最大值这个參数呢?
protected int getSuggestedMinimumWidth() {
int suggestedMinWidth = mMinWidth; if (mBGDrawable != null) {
final int bgMinWidth = mBGDrawable.getMinimumWidth();
if (suggestedMinWidth < bgMinWidth) {
suggestedMinWidth = bgMinWidth;
}
} return suggestedMinWidth;
}
<pre name="code" class="java"><span style="font-family: Arial, Helvetica, sans-serif;">android.view.View.View(Context, AttributeSet, int)
</span>
<span style="font-family: Arial, Helvetica, sans-serif;"> case R.styleable.View_minWidth:</span>
mMinWidth = a.getDimensionPixelSize(attr, 0);
break;
2. 接下来看getDefaultSize();这里依据measureSpec 的模式,假设是EXACTLY 精确模式 和 AT_MOST 最大模式,则使用 specSize 。否则使用传入的參数,就是刚才计算的getSuggestedMinimumWidth(),max(设置的最小宽高值, 背景宽高)
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:
result = size;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = specSize;
break;
}
return result;
}
3 所以在xml 文件里设置了宽高属性。默认的计算结果就是specSize。
对于rootViewImpl 来说。LayoutParams.MATCH_PARENT 和LayoutParams.WRAP_CONTENT
都是 windowSize, 否则就是lp 的宽高,也就是mWindowAttributes
WindowManager.LayoutParams lp = mWindowAttributes;
而mWindowAttributes的赋值是在android.view.ViewRootImpl.setView(View, LayoutParams, View) 中的copyfrom(); 也就是根view 的属性。就是初始view的属性。
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
synchronized (this) {
if (mView == null) {
mView = view;
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
那么,究竟这个ViewRootImpl是哪里来的呢,又有什么用处? to be continued...
讨论怎样重写onMeasure()方法
看完上面的系统默认的处理方式。
以及google 攻城狮 处心积虑留下的凝视来看。能做就是提供to provide better measurements of their content. 由于内容是自己自己定义的,所以就应该依照自己的需求来计算宽高喽。
并遵循系统的要求。1.确保大于min值;2. 在onMeasure()中调用setMeasuredDimension(int, int) 来保存计算的宽高的结果
留个尾巴
分析过程中ViewRootImpl是哪里来的呢,又有什么用处? to be continued...
版权声明:本文博主原创文章。博客,未经同意不得转载。
源代码分析:LayoutParams的wrap_content, match_parent, 而详细的价值观的更多相关文章
- 源代码分析:onAttach, onMeasure, onLayout, onDraw 的顺序。
从前文<源代码解析:dialog, popupwindow, 和activity 的第一个view是怎么来的?>中知道了activity第一个view或者说根view或者说mDecorVi ...
- 协议的注冊与维护——ndpi源代码分析
在前面的文章中,我们对ndpi中的example做了源代码分析.这一次我们将尽可能深入的了解ndpi内部的结构和运作.我们将带着以下三个目的(问题)去阅读ndpi的源代码. 1.ndpi内部是怎么样注 ...
- Media Player Classic - HC 源代码分析 7:详细信息选项卡(CPPageFileInfoDetails)
===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...
- Spark SQL 源代码分析之Physical Plan 到 RDD的详细实现
/** Spark SQL源代码分析系列文章*/ 接上一篇文章Spark SQL Catalyst源代码分析之Physical Plan.本文将介绍Physical Plan的toRDD的详细实现细节 ...
- Openck_Swift源代码分析——添加、删除设备时算法详细的实现过程
1 初始加入设备后.上传Object的详细流程 前几篇博客中,我们讲到环的基本原理即详细的实现过程,加入我们在初始创建Ring是执行例如以下几条命令: •swift-ring-builder obj ...
- Android 中View的绘制机制源代码分析 一
尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差点儿相同半年没有写博客了,一是由于工作比較忙,二是认为没有什么内容值得写, ...
- Android 中View的绘制机制源代码分析 二
尊重原创:http://blog.csdn.net/yuanzeyao/article/details/46842891 本篇文章接着上篇文章的内容来继续讨论View的绘制机制,上篇文章中我们主要解说 ...
- Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析
[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setCont ...
- Eoeclient源代码分析---SlidingMenu的使用
Eoeclient源代码分析及代码凝视 使用滑动菜单SlidingMenu,单击滑动菜单的不同选项,能够通过ViewPager和PagerIndicator显示相应的数据内容. 0 BaseSlid ...
随机推荐
- svn强制用户提交时写日志
#!/bin/sh REPOS="$1" TXN="$2" SVNLOOK=/usr/bin/svnlook #根据你的SVN目录而定 LOGMSG=`$SVN ...
- 不是技术牛人,如何拿到国内IT巨头的Offer(转)
不久前,byvoid面阿里星计划的面试结果截图泄漏,引起无数IT屌丝的羡慕敬仰.看看这些牛人,NOI金牌,开源社区名人,三年级开始写Basic…在跪拜之余我们不禁要想,和这些牛人比,作为绝大部分技术屌 ...
- Apache commons-net用法的一个示例
jar: commons-io-2.4.jarcommons-net-3.3.jar Code: import java.io.File; import java.io.FileInputStream ...
- leetcode第一刷_Largest Rectangle in Histogram
非常难的问题,数组线性时间. 属于我之前说的解法的借助辅助空间.给定两个柱子,他们之间的面积由什么确定呢?没错,他们之间的距离和他们之间最矮的那个柱子的高度.我们并不知道这个柱子在什么位置,所以仅仅能 ...
- 事件总线帧---Otto
我们如果这样一种业务场景.如今在做一款及时聊天应用,我们在聊天页面进行收发信息.同一时候也要实时更新前一页面的聊天记录,这时我们该怎样去实现?说说我曾经的实现策略.我使用的是广播接收器BroadCas ...
- Android 开源项目源码解析(第二期)
Android 开源项目源码解析(第二期) 阅读目录 android-Ultra-Pull-To-Refresh 源码解析 DynamicLoadApk 源码解析 NineOldAnimations ...
- Doxgen+Graphiz+htmlhelp配置
查看一些开源码常常被一些函数的调用关系给绕进去.找个工具生成个调用关系图或简单的文档对于帮助阅读程序有非常大的帮助. 1 doxgen+graphviz+htmlhelp简单介绍 1.1 doxgen ...
- HDU 3699 A hard Aoshu Problem (暴力搜索)
题意:题意:给你3个字符串s1,s2,s3;要求对三个字符串中的字符赋值(同样的字符串进行同样的数字替换), 替换后的三个数进行四则运算要满足左边等于右边.求有几种解法. Sample Input 2 ...
- Libevent使用样例,从简单到复杂
转载请注明出处:http://blog.csdn.net/luotuo44/article/details/39670221 本文从简单到复杂.展示怎样使用libevent.网上的很多 ...
- hdu1166(线段树)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 线段树功能:update:单点增减 query:区间求和 #pragma comment(lin ...