您的位置:首页 > 运维架构 > 网站架构

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

2018-03-12 21:25 375 查看

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐