Android UI的核心是由View和ViewGroup构成的树形结构:
// 自定义View测量示例
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val minWidth = 100.dpToPx() // 最小宽度
val width = when (MeasureSpec.getMode(widthMeasureSpec)) {
MeasureSpec.EXACTLY -> MeasureSpec.getSize(widthMeasureSpec)
MeasureSpec.AT_MOST -> minOf(minWidth, MeasureSpec.getSize(widthMeasureSpec))
else -> minWidth // UNSPECIFIED
}
setMeasuredDimension(width, resolveHeight(heightMeasureSpec))
}
EXACTLY:match_parent/固定尺寸,子View必须使用给定尺寸
AT_MOST:wrap_content,子View不能超过指定尺寸
UNSPECIFIED:ScrollView测量子View等场景,无限制
确定视图在布局中所在的位置
// 自定义ViewGroup布局实现
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var topPos = paddingTop
for (i in 0 until childCount) {
val child = getChildAt(i)
if (child.visibility != GONE) {
val childHeight = child.measuredHeight
child.layout(
paddingLeft,
topPos,
paddingLeft + child.measuredWidth,
topPos + childHeight
)
topPos += childHeight + spacing
}
}
}
绘制顺序源码解析:
public void draw(Canvas canvas) {
// Step 1. 绘制背景
drawBackground(canvas);
// Step 2. 保存图层(可选)
if (!dirtyOpaque) onDraw(canvas);
// Step 3. 绘制子View
dispatchDraw(canvas);
// Step 4. 绘制装饰(滚动条等)
onDrawForeground(canvas);
}
事件传递的一个UML序列图:
dispatchTouchEvent(MotionEvent ev)
, onInterceptTouchEvent(MotionEvent ev)
(仅 ViewGroup), onTouchEvent(MotionEvent ev)
。onInterceptTouchEvent
决定是否拦截事件,不拦截则向下分发 (dispatchTouchEvent
到子 View);子 View 通过 onTouchEvent
决定是否消费事件,不消费则向上回传。onInterceptTouchEvent
;内部拦截法 - 子 View 配合 requestDisallowInterceptTouchEvent
)。原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。