前言:

前面我们已经学过《Android 自定义 view(三)—— onDraw 方法理解》,那么接下我们还需要继续去理解自定义view里面的onMeasure 方法

推荐文章:

http://blog.csdn.net/a396901990/article/details/36475213?utm_source=tuicool&utm_medium=referral

onMeasure 作用

(1)一般情况重写onMeasure()方法作用是为了自定义View尺寸的规则,如果你的自定义View的尺寸是根据父控件行为一致,就不需要重写onMeasure()方法
(2)如果不重写onMeasure方法,那么自定义view的尺寸默认就和父控件一样大小,当然也可以在布局文件里面写死宽高,而重写该方法可以根据自己的需求设置自定义view大小

认识 onMeasure

(0)onMeasure (int widthMeasureSpec, int heightMeasureSpec)是view自己的方法

(1)onMeasure 方法简单的理解就是是用于测量视图的大小,主要是用来测量自己和内容的来确定宽度和高度

(2)onMeasure有两个参数 ( int widthMeasureSpec, int heightMeasureSpec),该参数表示控件可获得的空间以及关于这个空间描述的元数据.

(3)widthMeasureSpec和heightMeasureSpec这两个值通常情况下都是由父视图经过计算后传递给子视图的,说明父视图会在一定程度上决定子视图的大小。

认识 MeasureSpec

在测量自定义view的大小之前,我们需要认识一个类MeasureSpec,它封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求  MeasureSpec由size和mode组成。

specMode一共有三种类型,如下所示:
1. EXACTLY
表示父视图希望子视图的大小应该是由specSize的值来决定的,系统默认会按照这个规则来设置子视图的大小,简单的说(当设置width或height为match_parent时,模式为EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的)
2. AT_MOST
表示子视图最多只能是specSize中指定的大小。(当设置为wrap_content时,模式为AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸)

3. UNSPECIFIED
表示开发人员可以将视图按照自己的意愿设置成任意的大小,没有任何限制。这种情况比较少见,不太会用到。

onMeasure 之我见示意图

 

onMeasure  实践练习

要去自定义控件上面写一段文字,根据宽度

/**
* Created by yishujun on 16/6/5.
*/
public class YView extends View {
    private Context mContext;
    //定义一个paint
    private Paint mPaint;

    private String mText = "测试文字,自定义view";
    //绘制时控制文本绘制的范围
    private Rect mBound;

    public YView(Context context) {
        this(context, null);
    }

    public YView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public YView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        mBound = new Rect();
        mPaint = new Paint();
        mPaint.setTextSize(60);
        mPaint.getTextBounds(mText, 0, mText.length(), mBound);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.GRAY);
        mPaint.setColor(Color.RED);
        canvas.drawText(mText, getWidth() / 2 - mBound.width() / 2, getHeight() / 2 + mBound.height() / 2, mPaint);

    }

    /**
     * 比onDraw先执行
     * <p>
     * 一个MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。
     * 一个MeasureSpec由大小和模式组成
     * 它有三种模式:UNSPECIFIED(未指定),父元素部队自元素施加任何束缚,子元素可以得到任意想要的大小;
     * EXACTLY(完全),父元素决定自元素的确切大小,子元素将被限定在给定的边界里而忽略它本身大小;
     * AT_MOST(至多),子元素至多达到指定大小的值。
     * <p>
     * 它常用的三个函数:
     * 1.static int getMode(int measureSpec):根据提供的测量值(格式)提取模式(上述三个模式之一)
     * 2.static int getSize(int measureSpec):根据提供的测量值(格式)提取大小值(这个大小也就是我们通常所说的大小)
     * 3.static int makeMeasureSpec(int size,int mode):根据提供的大小值和模式创建一个测量值(格式)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        final int minimumWidth = getSuggestedMinimumWidth();
        final int minimumHeight = getSuggestedMinimumHeight();
        Log.e("YView", "---minimumWidth = " + minimumWidth + "");
        Log.e("YView", "---minimumHeight = " + minimumHeight + "");
        int width = measureWidth(minimumWidth, widthMeasureSpec);
        int height = measureHeight(minimumHeight, heightMeasureSpec);
        setMeasuredDimension(width, height);
    }

    private int measureWidth(int defaultWidth, int measureSpec) {

        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        Log.e("YViewWidth", "---speSize = " + specSize + "");

        switch (specMode) {
            case MeasureSpec.AT_MOST:
                defaultWidth = (int) mPaint.measureText(mText) + getPaddingLeft() + getPaddingRight();

                Log.e("YViewWidth", "---speMode = AT_MOST");
                break;
            case MeasureSpec.EXACTLY:
                Log.e("YViewWidth", "---speMode = EXACTLY");
                defaultWidth = specSize;
                break;
            case MeasureSpec.UNSPECIFIED:
                Log.e("YViewWidth", "---speMode = UNSPECIFIED");
                defaultWidth = Math.max(defaultWidth, specSize);
        }
        return defaultWidth;
    }

    private int measureHeight(int defaultHeight, int measureSpec) {

        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        Log.e("YViewHeight", "---speSize = " + specSize + "");

        switch (specMode) {
            case MeasureSpec.AT_MOST:
                defaultHeight = (int) (-mPaint.ascent() + mPaint.descent()) + getPaddingTop() + getPaddingBottom();
                Log.e("YViewHeight", "---speMode = AT_MOST");
                break;
            case MeasureSpec.EXACTLY:
                defaultHeight = specSize;
                Log.e("YViewHeight", "---speSize = EXACTLY");
                break;
            case MeasureSpec.UNSPECIFIED:
                defaultHeight = Math.max(defaultHeight, specSize);
                Log.e("YViewHeight", "---speSize = UNSPECIFIED");
//        1.基准点是baseline
//        2.ascent:是baseline之上至字符最高处的距离
//        3.descent:是baseline之下至字符最低处的距离
//        4.leading:是上一行字符的descent到下一行的ascent之间的距离,也就是相邻行间的空白距离
//        5.top:是指的是最高字符到baseline的值,即ascent的最大值
//        6.bottom:是指最低字符到baseline的值,即descent的最大值

                break;
        }
        return defaultHeight;

    }
}

第一组:

 

第二组:

Android 自定义 view(四)—— onMeasure 方法理解的更多相关文章

  1. Android自定义View的实现方法,带你一步步深入了解View(四)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到第四篇了,回 ...

  2. 【转】Android自定义View的实现方法,带你一步步深入了解View(四)

    原文网址: 转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/17357967 不知不觉中,带你一步步深入了解View系列的文章已经写到 ...

  3. Android 自定义View 四个构造函数详解

    https://blog.csdn.net/zhao123h/article/details/52210732 在开发android开发过程中,很多人都会遇到自定义view,一般都需要继承自View类 ...

  4. Android 自定义View (四) 视频音量调控

    转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24529807 今天没事逛eoe,看见有人求助要做一个下面的效果,我看下面一哥们说 ...

  5. android 自定义view 前的基础知识

    本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...

  6. Android 自定义 view(三)—— onDraw 方法理解

    前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...

  7. Android自定义View(三、深入解析控件测量onMeasure)

    转载请标明出处: http://blog.csdn.net/xmxkf/article/details/51490283 本文出自:[openXu的博客] 目录: onMeasure什么时候会被调用 ...

  8. Android自定义视图四:定制onMeasure强制显示为方形

    这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

  9. 【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10979161.html],谢谢! 尽管Android系统提供了不少控件,但是有很多酷炫效果仍然 ...

随机推荐

  1. zorka源码解读之通过beanshell进行插桩的流程

    zorka中插桩流程概述 1.在SpyDefinition中配置插桩属性,将SpyDefinition实例提交给插桩引擎.2.SpyDefinition实例中包含了插桩探针probes,probe插入 ...

  2. C#中UnixTime和DateTime的转换(转载)

    由于在API请求中返回回来的时间格式为UNIX形式,需要转换成正常的显示方式,在网上找到了这么一个例子. 使用是在C#中使用的,所以WP8开发应该也可以. 转载源地址:http://blog.linu ...

  3. JS:事件对象1

    一,this关键字和上下文 var box = document.getElementById("box");. 普通的函数如果没有给他传递参数,函数本身是没有参数的. test( ...

  4. SQLite部署-无法加载 DLL“SQLite.Interop.dll”: 找不到指定的模块

    近期刚使用SQLite,主要引用的是System.Data.SQLite.dll这个dll,在部署到测试环境时报无法加载 DLL“SQLite.Interop.dll”: 找不到指定的模块. (异常来 ...

  5. 在C#用HttpWebRequest中发送GET/HTTP/HTTPS请求

    通用辅助类  下面是我编写的一个辅助类,在这个类中采用了HttpWebRequest中发送GET/HTTP/HTTPS请求,因为有的时候需 要获取认证信息(如Cookie),所以返回的是HttpWeb ...

  6. 移动端/H5关于cursor:pointer导致的问题

    cursor属性规定要显示的光标的类型(形状),该属性定义了鼠标指针放在一个元素边界范围内时所用的光标形状(不过 CSS2.1 没有定义由哪个边界确定这个范围). 不过,这个属性用在PC端没有任何问题 ...

  7. css实现 当鼠标移到input的时候,input框出现阴影,当移动到button的时候,input框的阴影消失,button框出现阴影

    <meta charset="utf-8" /> <style type="text/css"> div{overflow: hidde ...

  8. DS实验题 融合软泥怪-1

    题目 思路 很容易想到第一种做法,用Huffman算法,从森林中找出两个值最小的节点,合并再加入森林,在这个过程中不断记录. 但是每一次需要sort一遍,将最小的两个值节点置于头两个节点,最坏情况下复 ...

  9. erlang调试之JCL

    Job control mode (JCL), in which jobs can be started, stopped, detached or connected. Only the curre ...

  10. python实现从生成器中取固定角标的元素

    #!/usr/bin/env python3 # -*- coding: utf-8 -*- class A: def __init__(self): def r(): i = 1 while Tru ...