第三章 Android控件架构与自定义控件详解

Android控件架构

在Activity中使用`setContentView(R.layout.activity_main)`来设置一个布局。

每个Activity都包含一个Window对象,在Android中Window对象通常由PhoneWindow来实现。PhoneWindow将一个DecorView设置整个应用窗口的根View,这里面所有的View监听事件,都由WindowMannagerService来进行接收,并通过Activity对象来回调相应的onClickListener。
DecorView将屏幕分为两部分,一个是TitleView,一个是ContentView。ContentView是一个ID为content的Framelayout,activity_main.xml就是设置在这样一个Framelayout中。
注意:当程序在onCreate()方法中调用setContentView(R.layout.activity_main)的时候,ActivityMannagerService会回调onResume(),此时系统才会把整个DecorView添加到PhoneWindow中。

View的测量

在测量的时候使用到一个类MeasureSpec,代表一个32位的int值,其中高2位代表测量的模式,低30位代表测量的大小。
测量模式一般是分三种:
AT_MOST:当控件的宽和高属性给定wrap_content的时候,使用的是该模式。
EXACTLY:当控件的宽和高给定一个具体值的时候,或者指定为match_parent的时候,系统使用的是该模式。
UNSPECIFIED:父容器不对view有任何限制,要多大就给多大,这种情况一般用于系统内部,表示一种测量的状态。
自定义View重写onMeasure()的时候,需要setMeasuredDimension()来设置控件的大小。例如:

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
    }

    private int measureHeight(int heightMeasureSpec) {
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        int result = 0;
        switch (heightMode){
            case MeasureSpec.AT_MOST:
                Log.i(TAG, "measureHeight: "+heightMode);
                result = 200;
                result = Math.min(heightSize, result);
                break;
            case MeasureSpec.EXACTLY:
                Log.i(TAG, "measureHeight: "+heightMode);
                result = heightSize;
                break;
        }
        return result;
    }

注意:如果没有重写onMeasure()方法,那么指定控件宽高为wrap_content无效,系统不知道应该使用多大的尺寸,将默认充满整个屏幕。

View的绘制

创建一个Canvas的时候,需要传入一个bitmap:

Canvas canvas = new Canvas(bitmap);//装载画布

这个bitmap用来存储所有绘制在canvas上的像素信息,canvas的drawXXX方法将会作用在这个bitmap上。

   重写onDraw方法,使用canvas的绘制API,但是其实并没有将图形绘制在onDraw()方法指定的那块画布上,
而是通过改变bitmap,然后让View重绘,显示改变之后的bitmap。

ViewGroup的测量与绘制

测量阶段:当ViewGroup的大小为wrap_content,ViewGroup首先会对子view进行遍历,获得子view的大小,然后决定自己的大小。而在其他模式下,则会通过具体的数值来设置自身的大小。
绘制阶段:如果没有指定ViewGroup的背景,那么onDraw()不会被调用;但是,ViewGroup会使用dispatchDraw()方法来绘制其子view,其过程同样是通过遍历所有子view,并调用子view的绘制方法来完成绘制工作。

自定义View

自定义View:
1:重写onDraw()来绘制View的显示内容。
2:如果该view使用 wrap_content , 还需要重写 onMeasure() 。
3:通过自定义attrs属性,可以设置新的属性配置值。使用 TypedArray 获取完属性的值后,要调用 TypedArray.recycle()

三种方式实现自定义的控件
1:对现有控件进行拓展。
2:通过组合来实现新的控件。(下个链接是一个topbar的小案例)

http://blog.csdn.net/ghdsq/article/details/79352111

3:重写view来实现全新的控件。
(1) 弧形展示图

http://blog.csdn.net/ghdsq/article/details/79353814

(2) 音频条形图

http://blog.csdn.net/ghdsq/article/details/79355944

自定义ViewGroup

自定义ViewGroup:
1:重写onMeasure()对子View进行测量。
2:重写onLayout()来确定子view的位置。
3:重写onTouchEvent()方法增加响应事件。
类似Android原生控件 ScrollView 的自定义 ViewGroup :

http://blog.csdn.net/ghdsq/article/details/79360238

事件拦截机制分析

http://blog.csdn.net/ghdsq/article/details/78985003

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值