您的位置:首页 > 移动开发 > Android开发

Android View之测量

2015-12-28 11:52 615 查看
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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: