自定义view(一)

来源:互联网 发布:600756 浪潮软件 编辑:程序博客网 时间:2024/05/20 18:00
  • 首先需要我们知道android的控件架构:
    这里写图片描述
    每一个activity都包含一个window对象,也就是phonewindow,phonewinodw把DecorView当做根视图,也就是顶层视图,所有view的监听事件,都通过WindowMannagerServer来进行接收的,并且通过activity对象来回调响应的onClickListener。那个title也就是平时的actionbar,ContentView就是我们天天都要接触的部分了。这也就解释了为什么要在setContentView前设置requestWindowFeature(Window.FEATURE_requestWindowFeature())在调用setContent方法前调用。
  • view的测量
    测量都是在onMeasure()方法中进行,需要用到MeasureSpec类,通过这个类我们可以拿到具体的测量模式和测量到的测量值。其中MeasureSpec是一个32位的int值,其中高2位位测量的模式,低30位是测量的大小。

  • 测量模式

    • EXACTLY
      精确模式,就是当我们制定控件的layout_width和layout_height属性为具体值时,android:layout_width=”200dp”, 同时也要注意了,如果是android:layout_width=“match_parent”时也是使用的该模式
    • AT_MOST
      这个可能就是用的最多的。最大值测量模式,在viewgroup的时候可能用的都是这个吧。当控件的layout_width和layout——height属性指定为wrap_content时,控件大小一般随着控件的子控件或者内容的变化而变化,此时控件的尺寸只要不超过父控件允许 的最大值即可
    • UNSPECIFIED
      这个其实也不太懂,通常情况下载绘制自定义view时候使用
  • view类默认的onMeasure()使用的方法只支持EXACTIY模式,所以在自定义的时候记得重写onMeasure()方法。不然控件只能响应具体的宽高和match_parent属性,没办法wrap_content。

演示代码

    ** * 描述:自定义view初步练习  ,自定义view最主要的就是 测量跟绘制, * 作者:Marc on 2016/5/27 09:07 *  */public class TechView extends View {    public TechView(Context context) {        super(context);    }    public TechView(Context context, AttributeSet attrs) {        super(context, attrs);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        //这里使用自定义的方法进行测量。        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeigth(heightMeasureSpec));    }    /**     * 自定义方法,对宽进行重新定义     *     * @param heightMeasureSpec 该对象中包含测量的模式和测量值的大小     * @return     */    private int measureHeigth(int heightMeasureSpec) {        int result = 0;        int specMode = MeasureSpec.getMode(heightMeasureSpec);//拿到测量模式        int specSize = MeasureSpec.getSize(heightMeasureSpec);//拿到测量大小        //通过判断测量的模式,给出不同的测量值        if (specMode == MeasureSpec.EXACTLY) {            //如果是精确值模式,就直接使用指定的specSize即可            result = specSize;        } else {            //如果不是精确值,是其他的2种模式            result = 200;            if (specMode == MeasureSpec.AT_MOST) {                // 尤其是AT_MOST 模式,也就是给定的是wrap_content属性,需要给一个默认值大小与测量出来的specSize中最小的那个                result = Math.min(result, specSize);            }        }        return result;    }    /**     * 测量宽度的方法     *     * @param widthMeasureSpec 该对象中包含测量的模式和测量值的大小     * @return     */    private int measureWidth(int widthMeasureSpec) {        int result = 0;        int specMode = MeasureSpec.getMode(widthMeasureSpec);//拿到宽度的测量模式        int specSize = MeasureSpec.getSize(widthMeasureSpec);//拿到宽度的测量值的大小        //通过判断测量模式给出测量值        if (specMode == MeasureSpec.EXACTLY) {            //如果是精确测量模式,那就直接给定测量出的值            result = specSize;        } else {            //如果是其他2种测量模式,就给个默认值            result = 200;            if (specMode == MeasureSpec.AT_MOST) {                //如果是AT_MOST模式也就是给定的是wrap_content模式,需要把result设置成默认值跟测量值中小的那个                result = Math.min(result, specSize);            }        }        return result;    }    /**     * 自定义view中绘制     *     * @param canvas     */    @Override    protected void onDraw(Canvas canvas) {        super.onDraw(canvas);        canvas.drawColor(Color.RED);//会成红色,这样子明显        int width = getWidth();        int height = getHeight();        Log.d("marc", "width ==" + width + ";height==" + height);    }- 结果```java    在布局中,如果指定具体宽高值,就是采用具体的。    指定match_parent就是充满父窗体    wrap_content属性时,如果不重写onMeasure()方法,系统不知道使用多大尺寸,就会默认填满父窗体。
0 0
原创粉丝点击