美文网首页程序员
Android群英传读书笔记(第三章)

Android群英传读书笔记(第三章)

作者: 青藤绿 | 来源:发表于2016-01-14 22:28 被阅读755次

    上一章

    第三章终于进入开发的正题了!本章主要介绍自定义控件:

    1.控件分为两类:ViewViewgroup,通过ViewGroup整个界面形成一个树形结构,并且ViewGroup负责对子View的测量与绘制以及传递交互事件。

    2.Activity包含一个Window对象,Window对象又将一个DecorView设置为整个应用的根View。这里所有View的监听事件都通过WindowManagerService来接收,并通过Activity对象来回调onClickListenerDecorView在显示上分为TitleViewContentView两部分。可以通过如下代码获得ContentView

    ViewGroup content=(ViewGroup)findViewById(android.R.id.content);
    

    3.View的测量在onMeasure中进行,系统提供了MeasureSpec类,是一个32位的int值,其高2位为测量模式,低30位为测量的大小。测量模式有以下三种:

    • EXACTLY:精确模式,当控件指定精确值(例如android:layout_width="50dp")或者指定为match_parent属性时系统使用该模式。
    • AT_MOST:最大值模式,指定wrap_content时系统使用该属性,View类默认只支持EXACTLY,如果想使用wrap_content需自己在onMeasure中实现。
    • UNSPECIFIED:自定义模式,View想多大就多大,通常在绘制自定义View的时候才使用。

    下面是onMeasure的事例代码:

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);// 获取宽度模式
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);// 获取宽度值
        int width = 0;
        if (widthMode == MeasureSpec.EXACTLY) {
            width = widthSize;
        } else {
            width = 200;// 自定义的默认wrap_content值
            if (widthMode == MeasureSpec.AT_MOST) {
                    width = Math.min(widthSize, width);
            }
    
        }
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);// 获取高度模式
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);// 获取高度值
        int height = 0;
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            height = 200;// 自定义的默认wrap_content值
            if (heightMode == MeasureSpec.AT_MOST) {
                height = Math.min(heightSize, height);
            }
        }
        setMeasuredDimension(width, height);// 最终将测量的值传入该方法完成测量
    }
    

    4.View的绘制是通过onDraw方法实现的,具体是通过对onDraw方法中canvas参数操作执行绘图。在其他地方,则需要自己创建canvas对象,创建时需传入一个bitmap对象, bitmap是用来保存Canvas.drawXXX绘制的像素信息的,通过这些绘图操作改变的实际上就是bitmap对象而不是canvas

    5.当ViewGroup的大小为wrap_content时,它就会遍历所有子View,并调用其Measure方法获得其大小,来决定自身的大小,而在其他模式下则通过指定值来设置自身的大小。然后当View测量完毕以后,ViewGroup会执行它的Layout方法,同样是遍历子View并调用其Layout方法来确定布局位置。在自定义ViewGroup时,通常会重写onLayout()方法来控制子View显示位置,若需支持wrap_content还需重写onMeasure()方法。ViewGroup通常情况下不需要绘制,但是会调用dispatchDraw()方法来绘制其子View,过程同样是遍历子View

    6.自定义View时有一些比较重要的回调方法如下:

    onFinishInflate();//从xml加载组件后回调
    onSizeChanged();//组件大小改变时回调
    onMeasure();//回调该方法进行测量
    onLayout();//回调该方法来确定显示的位置
    onTouchEvent();//监听到触摸事件回调
    

    7.自定义View通常有三种情况:
    (1)对现有控件进行拓展:
    一般来说,会在onDraw()方法中对原生控件行为进行拓展

    @Override
        protected void onDraw(Canvas canvas) {
            //在回调父类方法前,实现自己的逻辑
            super.onDraw(canvas);
            //在回调父类方法后,实现自己的逻辑
        }
    

    (2)通过组合来实现新的控件:
    这种方式通常需要继承一个合适的ViewGroup,再给它添加指定功能的控件,从而组合成新的复合控件。
    (3)重写View来实现全新的控件:
    当Android系统原生的控件无法满足我们的需求时,就需要创建一个全新的自定义View了。通常需要继承View类,并重写它的onDraw()onMeasure()等方法实现绘制逻辑,同时通过重写onTouchEvent()等触控事件来实现交互逻辑,还可以引入自定义属性,丰富自定义View的可定制性。

    8.本章较为浅显的分析了下事件传递的机制。当ViewGroup接收到事件,通过调用dispatchTouchEvent(),由这个方法再调用onInterceptTouchEvent()方法来判断是否要拦截事件,如果返回true则拦截将事件交给onTouchEvent处理,返回false则继续向下传递。当View在接受到事件时,通过调用dispatchTouchEvent(),由此方法再调用onTouchEvent方法,如果返回true则拦截事件自己处理,如果返回false则将事件向上传递回ViewGroup并且调用其onTouchEvent方法继续做判断。

    本章中用代码例举了很多自定义View,但由于本人对一些系统绘制的api尚不熟悉,等以后弄懂了再补充

    下一章

    相关文章

      网友评论

        本文标题:Android群英传读书笔记(第三章)

        本文链接:https://www.haomeiwen.com/subject/ybhhkttx.html