自定义view的测量onMeasure, 3种模式的处理

为什么要知道测试方法,测试模式呢?

因为自定义view在一下模式下面,需要自己对应的宽度和高度,或者需要自由的定义。

View类中的方法onMeasure() 是用来测量当前view的宽度和高度的, 3种模式说明

测量方法 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
测量模式int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);

MeasureSpec.UNSPECIFIED 不确定值
MeasureSpec.AT_MOST 最大值
MeasureSpec.EXACTLY 完全准确值

以一个列子来说明?
自定义view 通过测量控制view的宽度和高度,并draw图片的一个view

public class ThumbView extends View {

    private static final String TAG = "ThumbView";
    private Bitmap thumbUp;
    private Paint mBitmapPaint;
    private int startX;
    private int startY;

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

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

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

    private void init(){
        thumbUp = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_messages_like_selected);
        mBitmapPaint = new Paint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);//如果是继承的viewgroup比如linearlayout时,可以先计算
        int widthResult = 0;
        //view根据xml中layout_width和layout_height测量出对应的宽度和高度值,
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        switch (widthSpecMode){
            case MeasureSpec.UNSPECIFIED:
                widthResult = widthSpecSize;
                break;
            case MeasureSpec.AT_MOST://wrap_content时候
                widthResult = getContentWidth();
                break;
            case MeasureSpec.EXACTLY:
                //当xml布局中是准确的值,比如200dp是,判断一下当前view的宽度和准确值,取两个中大的,这样的好处是当view的宽度本事超过准确值不会出界
                //其实可以直接使用准确值
                widthResult = Math.max(getContentWidth(), widthSpecSize);
                break;
        }

        int heightResult = 0;
        int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
        switch (heightSpecMode){
            case MeasureSpec.UNSPECIFIED:
                heightResult = heightSpecSize;
                break;
            case MeasureSpec.AT_MOST://wrap_content时候
                heightResult = getContentHeight();
                break;
            case MeasureSpec.EXACTLY:
                heightResult = Math.max(getContentHeight(), heightSpecSize);
                break;
        }
        setMeasuredDimension(widthResult, heightResult);
    }

    /**
     * view中大拇指图片和padding的宽度, 就是自己本身包括的内容总的宽度
     */
    private int getContentWidth(){
        float contentWidth = thumbUp.getWidth()+getPaddingLeft()+getPaddingRight();
        Log.d(TAG, "getContentWidth: contentWidth="+contentWidth);
        return (int)contentWidth;
    }

    int getContentHeight(){
        float contentHeight = thumbUp.getHeight()+getPaddingTop()+getPaddingBottom();
        Log.d(TAG, "getContentWidth: contentHeight="+contentHeight);
        return (int)contentHeight;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
//        startX = w/2 - thumbUp.getWidth()/2 - getPaddingLeft()/2 -  getPaddingRight()/2;
//        startY = h/2 - thumbUp.getHeight()/2 - getPaddingTop()/2 -  getPaddingBottom()/2;
        Log.d(TAG, "onSizeChanged: w="+w+",h="+h+",startX="+startX+",startY="+startY);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //绘制图片
        canvas.drawBitmap(thumbUp, startX+getPaddingLeft(), startY+getPaddingTop(), mBitmapPaint);
    }
view实现会在XML布局文件中使用,有3中情况

1: android:layout_width="wrap_content"

布局文件,debug后,执行代码


图片.png

发现widthSpecMode 会对应到MeasureSpec.AT_MOST的模式,
发现widthSpecSize = 720px

所以当android:layout_width="wrap_content"时,对应MeasureSpec.AT_MOST的模式,而且系统自己计算的宽度是相当于match_parent的宽度,而我们自定义的view肯定是只要自己的宽度

自己的宽度 等于基本控件宽度+paddingLeft+paddingRight的宽度

图片.png

2: android:layout_width="match_parent", 等同于wrap_content的情况

3: android:layout_width="100dp"准确值

图片.png

当准确值的模式下,debug发现
发现测量模式MeasureSpec.EXACTLY
发现测量宽度widthSpecSize = 200px(布局文件100dp->200px)

所以当这种模式,自定的view的宽度,处理是直接获取自己的宽度,也可以自由点可以准确的值, 这里是取两个当中大的值,防止宽度太小导致view显示不全,这样保证了至少是view完整的大小

图片.png

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,874评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,102评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,676评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,911评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,937评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,935评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,860评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,660评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,113评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,363评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,506评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,238评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,861评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,486评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,674评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,513评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,426评论 2 352

推荐阅读更多精彩内容