一、什么是View?
1.View是用户接口组件的基本构建块;
2.View在屏幕上占据一个矩形区域;
3.View通过绘制自己与事件处理两种方式与用户交互
设计View,主要是为了让应用能够与用户交互,要想完成交互,这个View就要在屏幕上占据一个矩形区域,然后利用这块屏幕区域与用户交互,交互的方式就两种,绘制自己与事件处理。
二、如何管理View?
Google的解决方案是:首先,一套完整的用户界面用一个Window来表示,Window首先加载一个超级复合View,用它来包含住所有的其他View,这个超级复合View就叫做DecorView。
不同的View为了完成自己的交互任务所需要的屏幕区域大小是不同的,所以DecorView在确定给每个View分配的屏幕区域大小时,是允许View参与进来,与它一起商量的。但是每个View在屏幕区域中的位置就不能让View自己来决定了,而是由DecorView一手操办。
Activity中window和decorview的加载流程:
- Activity管理着Window,Window管理着DecorView,Activity间接管理着DecorView
- Activity处在“create"状态的时候创建对应的Window,并在setContentView里创建 DecorView,最终添加自定义布局到DecorView里。此时,Activity创建完毕,Window创建完毕,DecorView创建完毕,ViewTree构建成功,三者关系已建立。
- Acitivity处在“resume"状态的时候,通过Window的管理类将DecorView添加到Window里,并提交更新DecorView的请求。当下次屏幕刷新信号到来之时,执行ViewTree三大流程(测量,布局,绘制),最终的效果就是我们的自定义布局显示在屏幕上。 “注”:指的状态执行时机是处在ActivityThread里的。
2.1 确定每个View的位置
虽然View无法决定自己在ViewGroup中的位置,但是开发者在使用View时,可以向ViewGroup表达自己所用的View要放在哪里。(xml 布局文件)
2.2 确定View大小
2.2.1 开发者向ViewGroup表达的,我这个View需要的大小是多少;
2.2.2 ViewGroup收到了开发者对View大小的说明,然后ViewGroup会综合考虑自己的空间大小以及开发者的请求,然后生成两个MeasureSpec对象(width与height)传给View,这两个对象是ViewGroup向子View提出的要求;两个对象将会传到子View的protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
方法中
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int desiredWidth = // 计算所需宽度;
int desiredHeight = // 计算所需高度;
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int width, height;
if (widthMode == MeasureSpec.EXACTLY) {
// 确切的宽度
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
// 宽度不超过所需尺寸
width = Math.min(desiredWidth, widthSize);
} else {
// 未指定宽度
width = desiredWidth;
}
if (heightMode == MeasureSpec.EXACTLY) {
// 确切的高度
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
// 高度不超过所需尺寸
height = Math.min(desiredHeight, heightSize);
} else {
// 未指定高度
height = desiredHeight;
}
setMeasuredDimension(width, height);
}
其中莫得还有第三种标志位:UNSPECIFIED 它表示,你自己看着办,把你最理想的大小告诉我,我考虑考虑
三、自定义View
3.1 什么是自定义View
自定义View是Android开发中的重要概念,允许你创建不同于标准UI组件的用户界面元素。这些自定义View可以是各种形状、颜色和交互方式,完全满足你的设计需求。
3.2 创建自定义View
步骤1: 继承View类或其子类
要创建自定义View,首先需要继承自Android的View
类或其子类,如ViewGroup
。根据需要,你还可以继承更具体的子类,如TextView
、ImageView
等实现自定义控件。以下是一个简单的示例:
public class MyCustomView extends View {
public MyCustomView(Context context) {
super(context);
}
}
步骤2: 重写onMeasure
方法
你需要重写onMeasure
方法来定义自定义View的尺寸。这个方法决定了View的宽度和高度,通常基于View的内容和布局需求计算测量值。如上2.2代码
步骤3: 重写onDraw
方法
onDraw
方法用于绘制自定义View的内容。在这里,你可以使用Canvas
对象进行绘制操作,包括绘制形状、文本、位图等。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 绘制自定义UI
Paint paint = new Paint();
paint.setColor(Color.RED);
canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
}
步骤4: 在XML布局中使用自定义View
步骤5: 在Java代码中操作自定义View
3.3 优化方向
3.3.1 使用硬件加速
3.3.2 避免不必要的绘制
3.3.3 使用合适的绘制方法 drawPath,drawBitmap
3.3.4 处理触摸事件:如果需要自定义View响应触摸事件,可以重写onTouchEvent
方法,处理触摸事件逻辑。
3.3.5 多线程优化