-“爹,我要吃糖”
-“好哒儿子”
-“爹,我要吃包包”
- “好哒儿子”
- “爹,我要吃串串”
- “好哒儿子”
- “爹,我要大保健”
- (啪啪啪,三耳光)

儿子是一定要听爹话的,那么在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>

[置顶] Android轶事之View要去大保健?View大小自己决定?_第1张图片
可以看到,在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要去大保健?View大小自己决定?_第2张图片

呃呃呃。。。看来在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>

那么你就会发现。。
[置顶] Android轶事之View要去大保健?View大小自己决定?_第3张图片

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处理。

呃呃。。跑题了。。。 好吧,没啥说的了,写这篇文章就是告诉大家一个道理。儿子就得听爹的话。。。 拜拜。如果你喜欢我的博客,记得关注我。

更多相关文章

  1. Android Glide缓存清除与获取缓存大小
  2. android webview设置内容的字体大小
  3. Android Zxing修改二维码中扫描框的大小仿微信
  4. android 动态改变控件大小的方法
  5. EditText的字体和大小
  6. Android中如何比较两个时间值的大小.
  7. android中Bitmap图像处理 修改图片大小以及保存时的文件大小
  8. android 写布局的时候注意大小写
  9. android取得手机屏幕大小DisplayMetrics的核心代码

随机推荐

  1. NDK编译Android字符界面的可执行程序
  2. Android访问服务器
  3. Android(安卓)网络连接——URLConnection
  4. Android快速入门
  5. Android(安卓)Material Design 之CardVie
  6. No 97 · 在Android中查看和管理sqlite数
  7. android异步网络连接开源:Android(安卓)As
  8. android中wifi原理及流程分析
  9. Android中Shape和selector的使用
  10. 自己收藏的Android开发的知识点各种传送