一、概念
View | 代表用户界面组件的基本构建块,在屏幕上占据一个矩形区域并负责绘制和事件处理,是用于创建交互式用户界面组件(按钮、文本等)的基础类,因此我们使用的各种控件其实就是在 View 的基础上又添加了各自特有的功能。 |
ViewGroup | 继承自View,它可以包含很多子View和子ViewGroup,是一个用于放置控件和布局的容器。 |
二、类中方法
构造 | View(Context context) 单参构造:代码中 new 创建实例的时候调用。 |
View(Context context, AttributeSet attrs) 双参构造:xml中使用时调用(xml转java代码的时候反射),attrs是xml中的属性。 | |
View(Context context, AttributeSet attrs, int defStyleAttr) 三参构造:使用主题Style的时候调用。 | |
绘制过程 | onFinishInflate() 当View和他的所有子控件被XML布局文件填充完成时被调用。(这个方法里面可以完成一些初始化,比如初始化子控件)。 |
onMeasure() 当测量View和它的子View的尺寸需求时被调用。 | |
onLayout() 当View给他的子View分配大小和位置的时候调用。 | |
onSizeChanged() 当view尺寸发生变化时调用。 | |
事件处理 | onKeyDown(int keyCode, KeyEvent event) 按下按键时调用,keyCode是按键编号,KeyEvent是按键事件。 |
onKeyUp(int keyCode, KeyEvent event) 抬起按键时调用。 | |
onTouchEvent(MotionEvent event) 触摸屏幕时调用,MotionEvent是捕捉到的触摸事件。 | |
焦点 | onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) 获取到或者失去焦点时调用。 |
onWindowFocusChanged(boolean hasWindowFocus) 窗口获取或者失去焦点时调用。 | |
attach | onAttachedToWindow() 当View被连接到一个窗口时调用。 |
onDetachedFromWindow() 当View从窗口分离时调用。 | |
onWindowVisibilityChanged() 当View的窗口的可见性发生改变时调用。 |
2.1 构造
没有空参构造必须重写,一共有四种(四参构造在 API21 加入)对应不同的创建方式。一般只需要重写前三个,通过 this 调用到三参构造中统一进行处理。
View(Context context) 单参构造:代码中 new 创建实例的时候调用。 |
View(Context context, AttributeSet attrs) 双参构造:xml中使用时调用(布局文件映射成java对象,反射),attrs是xml中的属性需要解析。 |
View(Context context, AttributeSet attrs, int defStyleAttr) 三参构造:使用主题Style的时候调用。 |
class MyView : View {
//改成this调用2个参数的构造
constructor(context: Context?) : this(context, null)
//改成this调用3个参数的构造
constructor(context: Context?, attrs: AttributeSet?) : this(context, attrs, 0)
//在3个参数的构造里统一进行处理
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
//TODO...
}
}
2.2 绘制过程
onFinishInflate() | 当View和他的所有子控件被XML布局文件填充完成时被调用。(这个方法里面可以完成一些初始化,比如初始化子控件)。 |
onMeasure() | 当测量View和它的子View的尺寸需求时被调用。 |
onLayout() | 当View给他的子View分配大小和位置的时候调用。 |
onDraw() | 当绘制View时调用。 |
onSizeChanged() | 当view尺寸发生变化时调用。 |
2.3 事件处理
onKeyDown() | onKeyDown(int keyCode, KeyEvent event) 按下按键时调用,keyCode是按键编号,KeyEvent是按键事件。 |
onKeyUp() | onKeyUp(int keyCode, KeyEvent event) 抬起按键时调用。 |
onTouchEvent() | onTouchEvent(MotionEvent event) 触摸屏幕时调用,MotionEvent是捕捉到的触摸事件。(当View带有滑动嵌套情况时,必须要处理好滑动冲突,否则会严重影响View的显示效果。) |
2.4 子元素
添加子元素,除了在 xml 中包裹,还能用如下代码添加。
removeView() | public void removeView(View view) 移除某个子元素。 |
removeAllViews() | public void removeAllViews() 清空所有子元素。 |
addView() | public void addView(View child) 添加子元素。 |
fun setData(list: List<String>) {
removeAllViews()
for(i in list) {
val textView = TextView(getContext())
textView.text = list[i]
addView(textView)
}
}
五、焦点
onFocusChanged() | onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) 获取到或者失去焦点时调用。 |
onWindowFocusChanged() | onWindowFocusChanged(boolean hasWindowFocus) 窗口获取或者失去焦点时调用。 |
findFocus() | public View findFocus() 获取当前拥有焦点的控件,注意空判断。 |
六、避免内存泄漏 attach
针对View中含有线程或动画的情况:当View退出或不可见时,记得及时停止该View包含的线程和动画,否则会造成内存泄露问题。
onAttachedToWindow() | 当包含该View的Activity启动的时调用,可用于启动线程/ 动画。 |
onDetachedFromWindow() | 当包含该View的Activity退出或该View被remove的时调用,可用于停止线程/动画。 |
onWindowVisibilityChanged() | 当包含该View的窗口的可见性发生改变时调用。 |
七、多线程
View的内部本身提供了post系列的方法,完全可以替代Handler的作用,使用起来更加方便、直接。
post() |