• Android 自定义 view(四)—— onMeasure 方法理解


    前言:

    前面我们已经学过《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 之我见示意图

    image

    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;


        }
    }

    第一组:

    {4C40CF2B-25DA-8096-C52F-E8F2520A14E8}

    {E417DA7A-21FA-440C-82D5-CE896F38EB83}

    {9315B26B-8826-AB33-1CF1-A8FA872940EB}

    第二组:

    {1F4378AB-04E5-BCC2-FA22-7ACBD33F9715}

    {26A41B85-0661-E8F6-64FE-79E1A4216B9D}

    {624CCB2E-B126-A907-F93B-8B0793E08A66}

    {6A2BFBA6-0584-A507-1CD2-F172451DE606}

  • 相关阅读:
    P1772 [ZJOI2006]物流运输
    P3951 小凯的疑惑
    P1082 同余方程(【模板】exgcd)
    T107741 【模板】权值线段树合并
    P3205 [HNOI2010]合唱队
    P1062 数列
    P1144 最短路计数
    P1502 窗口的星星
    P4147 玉蟾宫(【模板】悬线法)
    CSP模拟赛#3 分段(T1-26)
  • 原文地址:https://www.cnblogs.com/yishujun/p/5560838.html
Copyright © 2020-2023  润新知