android 自定义控件基础之三种约束类型

android onMeasure() 三种约束类型

先不说太多的概念,希望通过一个简单的demo来理解这三种类型。

测试Demo

OnMeasureLayout.java

package com.example.lcj.myapplication;


import android.content.Context;
import android.util.AttributeSet;
import android.widget.LinearLayout;


public class OnMeasureLayout extends LinearLayout {
    private static final String TAG = "OnMeasureLayout";

    public OnMeasureLayout(Context context) {
        super(context);
    }

    public OnMeasureLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public OnMeasureLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

以上很简单的代码就是一个继承了LinearLayout 重写了构造方法和onMeasure方法,我们主要分析的就是onMeasure传过来的两个参数widthMeasureSpec与heightMeasureSpec。我先把代码粘完~
activity_main.xml

<com.example.lcj.myapplication.OnMeasureLayout
    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"
    tools:context=".MainActivity"
    android:background="@android:color/holo_blue_light"
    >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="LCJLCJ"
        android:textSize="150sp"
        />

</com.example.lcj.myapplication.OnMeasureLayout>

xml布局中引用OnMeasureLayout。
MainActivity.java

package com.example.lcj.myapplication;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

这个不说了,你懂的…

好运行看一下效果:

ok,没有问题,我们简单改一下OnMeasureLayout.java中的onMeasure()方法:

   @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        //取出宽的MeasureSpec 中的size(大小) 和 mode(约束类型)
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        //判断约束类型并打印输出
        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                Log.d(TAG, "MeasureSpec.UNSPECIFIED");
                break;
            case MeasureSpec.AT_MOST:
                Log.d(TAG,"MeasureSpec.AT_MOST");
                break;
            case MeasureSpec.EXACTLY:
                Log.d(TAG,"MeasureSpec.EXACTLY");
                break;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

因为widthMeasureSpec 与 heightMeasureSpec 分析方法是一样的,我们就只分析宽度的MeasureSpec就可以了。MeasureSpec 中有两个信息,size(大小) 和 mode(约束类型)。那么我们现在通过上面的代码取出MeasureSpec 中的两个信息进行分析。

好,我们再运行代码看一下Log:
12952-12952/com.example.lcj.myapplication D/OnMeasureLayout﹕ MeasureSpec.EXACTLY
12952-12952/com.example.lcj.myapplication D/OnMeasureLayout﹕ MeasureSpec.EXACTLY

我们看到是 EXACTLY,测量会进行多次。

好,接的我们改一下activity_main.xml中的代码

<com.example.lcj.myapplication.OnMeasureLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="250dp"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="@android:color/holo_blue_light"
    >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="LCJLCJ"
        android:textSize="150sp"
        />

</com.example.lcj.myapplication.OnMeasureLayout>

将….OnMeasureLayout 的宽度设置为250dp ,再次运行看Log
这里写图片描述
效果如上,再看一下Log:
26504-26504/? D/OnMeasureLayout﹕ MeasureSpec.EXACTLY
26504-26504/? D/OnMeasureLayout﹕ MeasureSpec.EXACTLY

也是EXACTLY ,到这里我们发现 match_parent 和 固定值250dp 的约束类型都是 EXACTLY ,exactly字面意思就是准确地、恰好地 、等,也就是说对子view来说,给定的大小已经限定了,就这么大。这就是EXACTLY的约束能力,有点强硬。(match_parent 默认值最大就是手机屏幕了,不多说)

好接下来想必你也知道了,我们改成wrap_content 看看Log:

<com.example.lcj.myapplication.OnMeasureLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:context=".MainActivity"
    android:background="@android:color/holo_blue_light"
    >

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="LCJLCJ"
        android:textSize="150sp"
        />

</com.example.lcj.myapplication.OnMeasureLayout>

运行效果:
这里写图片描述
18270-18270/? D/OnMeasureLayout﹕ MeasureSpec.AT_MOST
18270-18270/? D/OnMeasureLayout﹕ MeasureSpec.AT_MOST
ok,wrap_content 的约束类型是 AT_MOST,wrap_content 是包裹内容,大家都比较熟悉了,那么at_most跟包裹内容有毛关系呢?先来看看at_most 字面意思:最多、至多、等。
那么,最多到哪啊?其实wrap_content 的最多默认到父布局的宽高,那么match_parent 不也是默认到父布局的宽高么?区别在哪里,其实区别从运行效果上来看最简单了,对于wrap_content 约束能力来说就是
子view用多少就给多少,别超过最大值就行。而对于match_parent 不管你子view 的使用情况,就给你这么大!

那么,还剩下UNSPECIFIED,我们继续改一下OnMeasureLayout.java中的onMeasure()方法:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        //取出宽的MeasureSpec 中的size(大小) 和 mode(约束类型)
        int specMode = MeasureSpec.getMode(widthMeasureSpec);
        int specSize = MeasureSpec.getSize(widthMeasureSpec);

        //判断约束类型并打印输出
        switch (specMode) {
            case MeasureSpec.UNSPECIFIED:
                Log.d(TAG, "MeasureSpec.UNSPECIFIED");
                break;
            case MeasureSpec.AT_MOST:
                Log.d(TAG,"MeasureSpec.AT_MOST");
                break;
            case MeasureSpec.EXACTLY:
                Log.d(TAG,"MeasureSpec.EXACTLY");
                break;
        }

        //修改宽度的约束类型 specSize 不变,修改约束类型为 UNSPECIFIED
        //MeasureSpec.makeMeasureSpec()用于组装一个 MeasureSpec 简单带过。
        int myWidthMeasureSpec = MeasureSpec.makeMeasureSpec(specSize,MeasureSpec.UNSPECIFIED);
        super.onMeasure(myWidthMeasureSpec, heightMeasureSpec);
    }

这里我们先看运行效果:
这里写图片描述
这里我们看到的效果就是textview不会换行了,再看看UNSPECIFIED 字面意思 : 不指定。
这也就意味着,对子view 没有任何约束,所以也就导致上图运行的效果,因为宽度没有了约束,那就疯狂的往外长了,UNSPECIFIED 什么控件有用到?ScrollVIew,高度上就是UNSPECIFIED ,因为能滚,任性~

总结

  • EXACTLY
    明确约束对子view大小由specSize的值来决定。

  • AT_MOST
    子view最多只能是specSize中指定的大小。

  • UNSPECIFIED
    对子view没有约束。

以上就是对三种测量约束类型的解析,大家可以把代码跑起来玩玩,这样会更好的理解。
接下来去分析相应的源码,加深理解层次。今天就到这!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值