[置顶] Android轶事之View要去大保健?View大小自己决定?
-“爹,我要吃糖”
-“好哒儿子”
-“爹,我要吃包包”
- “好哒儿子”
- “爹,我要吃串串”
- “好哒儿子”
- “爹,我要大保健”
- (啪啪啪,三耳光)
儿子是一定要听爹话的,那么在Android世界里,是不是这样呢? 今天就来和大家讨论一下 View 父子之间的琐事。
大家都知道,儿子肯定有自己想做的事情,也就是有自己的思想。那么转换到Android的View上面呢,就是测量啦。View自己会测量自己,告诉父布局他自身有多大,要占多大空间。可儿子就能胆大妄为,想怎么样就怎么样吗,答案是否定的。
View的最终大小不是由自己决定的,而是由layout决定。
这里我们来做一个实验。
比如,新写一个矩形自定义view:
public class RectView extends View { private Paint mPaint; private int mWidth; private int mHeight; public RectView(Context context) { this(context, null); } public RectView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RectView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mPaint = new Paint(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); if(widthMode == MeasureSpec.AT_MOST){ mWidth = 200; } if(heightMode == MeasureSpec.AT_MOST){ mHeight = 200; } setMeasuredDimension(mWidth,mHeight); } @Override protected void onDraw(Canvas canvas) { canvas.drawRect(0,0,mWidth,mHeight,mPaint); super.onDraw(canvas); }}
这里简单处理了一下 这个view的wrap_content时候的大小,写死为200px(注意是px不是dp)。
放到一个linearLayout下,看看效果
<?xml version="1.0" encoding="utf-8"?><LinearLayout 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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:orientation="vertical" tools:context="com.wingsofts.father.MainActivity"> <com.wingsofts.father.RectView android:layout_width="wrap_content" android:layout_height="wrap_content" /><Button android:layout_width="wrap_content" android:layout_height="wrap_content" /> <com.wingsofts.father.RectView android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>
可以看到,在wrap_content的情况下,两个view的大小跟自己预期的一样。(这种情况就是:“老爹,我想吃包子” “好哒儿子”)。
其实这篇文章的起源来与一个layout函数,大家都知道layout函数决定了一个view在什么位置。但是大家有没有想过,既然是先测量再layout的,为什么layout函数需要四个参数?既然测量知道view的大小了,那么只需要左上角x,y两个坐标不就好了吗?
layout(int l,int t,int r,int b);
难道测量的大小并不能真正决定view自己的大小吗?测量出来的值只是一个期望值,而不是最终的值吗,最终还是要听老爹话吗?我们来实验一下就知道了。(“老爹,我要大保健”)
自己新建一个viewgroup,继承自LinearLayout
public class MyLinear extends LinearLayout { public MyLinear(Context context) { this(context, null); } public MyLinear(Context context, AttributeSet attrs) { this(context, attrs, 0); } public MyLinear(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { //调用父类方法 super.onLayout(changed, l, t, r, b); //将第一个view布局到0,0,50,50位置 View v = getChildAt(0); v.layout(0,0,50,50); }}
这时候布局只是把LinearLayout改成MyLinear。
(儿贼,听说你要大保健,先来尝尝爹的大宝剑!咔咔咔嚓,给削小了)
呃呃呃。。。看来在android世界中,儿子也是要听老子的啊。一般的要求绝对满足,有非分之想,过不了老子那关啊。
- 再来个彩蛋吧。。
话说,大家一定有过一个拿空白View(其实用Space标签比较好)去占一定大小的经历(损招,但是有时候很好用)。。
比如通常希望一个空白view占据50dp的宽度,高度写为wrap_content 。
<LinearLayout 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" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.wingsofts.father.MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" /> <View android:layout_width="50dp" android:layout_height="wrap_content" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" /></LinearLayout>
那么你就会发现。。
WTF??? 为毛是全屏的高度。我写的是wrap_content啊。。难道View的wrap_content就是全屏??
不要急。。我们来read the fxxking source code ..
直接定位到view的onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); }
额。。没啥东西呀,继续跳到getDefaultSize()
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; }
呃呃。。 问:小白为什么长得像他哥哥。
这下真像大白了:原来,在View自身wrap_content(也就是AT_MOST模式),switch的case下面是没有break的,也就是说,
如果View没有处理AT_MOST模式,那么wrap_content自动当成match_parent处理。
呃呃。。跑题了。。。 好吧,没啥说的了,写这篇文章就是告诉大家一个道理。儿子就得听爹的话。。。 拜拜。如果你喜欢我的博客,记得关注我。
更多相关文章
- Android Glide缓存清除与获取缓存大小
- android webview设置内容的字体大小
- Android Zxing修改二维码中扫描框的大小仿微信
- android 动态改变控件大小的方法
- EditText的字体和大小
- Android中如何比较两个时间值的大小.
- android中Bitmap图像处理 修改图片大小以及保存时的文件大小
- android 写布局的时候注意大小写
- android取得手机屏幕大小DisplayMetrics的核心代码