Android View之测量

Android系统在绘制View之前,必须对View进行测量。Android提供的一个MeasureSpec类,来帮助我们测量View。MeasureSpec是一个32位的int值,其中高2位为测量的模式,低30位为测量的大小,在计算中使用位运算的原因是为了提供并优化效率,在自定义View的时候,同过重写onMeasure()方法来测量View的大小。

测试的模式为可以分为以下三种:

1、          EXACTLY(精确模式);即当我们为控件的高宽指定一个具体的大小,或者控件的高宽为匹配父控件的时候,系统使用的是EXACTLY。

2、          AT_MOST(最大模式);即当我们为控件的高宽的大小是包含内容的时候。

3、          UNSPECIFIED(不指定其大小模式) 这种这种情况不多,一般在父控件为AdpterView,通过measure方法传入的模式,因此在onMeasure()方法是要根据模式不同进行尺寸大小的计算。

   View默认的onMeasure方法只支持EXACTLY模式,所以在自定义View的时候,如果在自定义控件的时候不重写onMeasure方法的时候,使用的只能是EXACTLY模式。


冲View源码onMeasure()方法可以看出,系统通过setMeasureDimension(int measuredWidth,intmeasreHeght)方法来来测量高宽。

测量View的高宽的基本步骤:

1、 从MeasureSpec对象中提取拒听的测量模式与大小



2、 通过判断测量的模式,给出不同的测量值。




ViewGroup测量

  ViewGroup在管理其子View时,其中一个管理项目就是负责子View的显示大小。当ViewGroup的大小为wrap_content时,ViewGroup就需要对子View进行遍历,以便获取所有子View的大小,从而决定自己的大小。而在其他模式下则会通过具体指定的值来设置自身的大小。

ViewGroup在测量时通过遍历所有的子View,从而调用子View的Measure方法来获取每一个View的测量结果。当子View测量完毕之后,就需要将子View放到合适的位置,这个过程就是View的Layout过程。ViewGroup在执行Layout过程时,同样是使用遍历来调用子View的方法,并指定其具体的显示位置,从而来决定其布局位置。在自定义ViewGroup时,通常会去重写onLayout()方法来控制其子View显示位置的逻辑 。同样,如果需要支持wrap_content属性,则必须重写onMeasure方法。

ViewGroup通常情况下不需要绘制,因为它本身就没有需要绘制的东西,如果不是指定了ViewGroup的背景颜色,那么ViewGroup的onDraw()方法都不会调用。当时,ViewGroup会调用dispatchDraw()方法来绘制其子View,其过程同样是通过遍历所有的子View,并调用子View的绘制方法来完成绘制工作。

在自定义View时,我们通常会去重写onDraw()方法来绘制View的显示内容。如果该View使用wrap_content属性,那么还必须重写onMeasure()方法。在自定义View时比较几个重要的回调方法:

  onFinishInflate():从Xml加载组件后回调。

  onSizeChaged():组件大小改变的时候回调

 onMeasure():回调该方法进行测量(ViewGrop测量时会调用子View的Measure子View的测量)

 onLayout():回调该方法来确定显示位置。

 onTouchEvent():监听到触摸事件回调。

通常情况下,有以下三种方法来实现自定义的控件。

1、 对现有控件进行拓展。

2、 通过组合来实现新控件。

3、 重写View来实现全新的控件



package com.xiong.demo1;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

/**
 * Created by xionglh on 2015/12/25.
 */
public class MyView extends View {


    private Paint mPaint;

    public MyView(Context context, AttributeSet attributes) {
        super(context, attributes, 0);
        mPaint = new Paint();
        mPaint.setColor(Color.RED);
        mPaint.setTextSize(2);
        mPaint.setStyle(Paint.Style.FILL);
    }

    int mHegith;
    int mWidht;

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

        int wMode = MeasureSpec.getMode(widthMeasureSpec);//获取测量模式
        int hMode = MeasureSpec.getMode(heightMeasureSpec);
        int wSize = MeasureSpec.getSize(widthMeasureSpec);//获取测量的大小
        int hSize = MeasureSpec.getSize(heightMeasureSpec);
        if (wMode == MeasureSpec.EXACTLY) {
            mWidht = wSize;
        } else {
            mWidht = 400;
            mWidht = Math.min(mWidht, wSize);
        }
        if (hMode == MeasureSpec.EXACTLY) {
            mHegith = hSize;
        } else {
            mHegith = 400;
            mHegith = Math.min(mHegith, hSize);
        }
        setMeasuredDimension(mHegith, mHegith);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawRect(0, 0, mWidht,mHegith , mPaint);
    }
}


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <com.xiong.demo1.MyView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ssssssssssssssss"/>

</LinearLayout>



猜你喜欢

转载自blog.csdn.net/x605940745/article/details/50417955