dispatchDraw()和onDraw()的区别

本文通过一个具体的自定义View示例,展示了Android中onDraw()与dispatchDraw()的区别及应用。onDraw()用于控件本身的绘制,而dispatchDraw()则负责子控件的绘制。文章强调了使用dispatchDraw()来确保自定义View的绘制不会被子控件覆盖。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这些只是自己测试的一些发现和理解做个记录,如果那里不对还请不吝赐教

onDraw()先于dispatchDraw()执行,用于本身控件的绘制,dispatchDraw()用于子控件的绘制

onDraw()绘制的内容可能会被子控件覆盖而dispatchDraw()是子控件的绘制,所以是覆盖在onDraw()上的

布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">
    <com.example.myviewpage.ViewPagerIndicator
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="#999999"
        android:id="@+id/main_vpi">
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="标题1"
            android:background="#f00"
            android:gravity="center"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="标题2"
            android:gravity="center"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:text="标题3"
            android:gravity="center"/>
    </com.example.myviewpage.ViewPagerIndicator>
    <android.support.v4.view.ViewPager
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/mian_vp"/>
</LinearLayout>

ViwPagerIndicator是继承自LinearLayout的自定义控件目的是绘制一个三角形的指示器

ViwPagerIndicator使用dispatchDraw():

@Override
protected void dispatchDraw(Canvas canvas) {
    super.dispatchDraw(canvas);
    canvas.save();
    canvas.translate(minitTrianslationX+mTrianslationX,getHeight());
    canvas.drawPath(path,paint);
    canvas.restore();
    Log.i(TAG, "dispatchDraw: ");
}

效果:

ViwPagerIndicator使用dispatchDraw():

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    canvas.save();
    canvas.translate(minitTrianslationX+mTrianslationX,getHeight());
    canvas.drawPath(path,paint);
    canvas.restore();
    Log.i(TAG, "onDraw: ");
}

效果:


可以看出,这种情况是应该使用dispatchDraw()保证绘制的内容不被子控件覆盖

### Android 中 View 的绘制机制与加载流程 #### 测量阶段 (Measure) 在 Android 中,每个 `View` 都会经历三个主要阶段:测量、布局绘制。测量阶段由 `measure()` 方法负责,此方法用于确定 `View` 其子项的大小[^3]。 ```java protected void measure(int widthMeasureSpec, int heightMeasureSpec) { ... } ``` 在此期间,父级容器会给定宽度高度的规格 (`MeasureSpec`),这些规格包含了尺寸模式(精确值、最大值或未指定)以及具体的尺寸数值。这使得 `View` 能够根据可用空间调整自身的大小。 #### 布局阶段 (Layout) 一旦完成了测量操作,接下来便是布局阶段,即调用 `layout()` 来决定各个组件的具体位置。 ```java public void layout(int l, int t, int r, int b) { ... } ``` 这里指定了左、顶、右、底四个参数来定位 `View` 在屏幕上的确切区域。对于 `ViewGroup` 类型的对象而言,还需要对其内部所有的子元素重复上述两个步骤——先测量再安排它们的位置。 #### 绘制阶段 (Draw) 最后一步是绘制(`draw()`),这是真正把内容渲染到屏幕上的一环[^4]: ```java public void draw(Canvas canvas) { // Draw the background. // Call onDraw(). // Draw children via dispatchDraw(). // Draw decorations like scrollbars. } ``` 具体来说,绘制过程涉及以下几个方面: - **背景绘制**:设置并填充背景颜色或者图案; - **核心绘图逻辑**:通过重写 `onDraw()` 实现特定图形或文字等内容的呈现; - **子视图绘制**:利用 `dispatchDraw()` 处理嵌套结构内的其他控件; - **装饰性元素**:比如滚动条等附加特性也会在这个时候被添加上去。 #### 启动与初始化 当应用程序启动一个新的 Activity 时,在 `ActivityThread.java` 文件里的 `handleResumeActivity()` 函数会被触发,从而开启整个 UI 渲染链条。最终到达 `ViewRootImpl.performTraversals()` 这个关键入口点,标志着正式进入到了前面提到过的 Measure/Layout/Draw 循环之中[^5]。 #### 总体流程总结 综上所述,Android 应用程序中任何可视化的交互界面都是基于这套严格的分层架构来进行构建管理的。从最顶层的根节点开始逐层向下传递消息直至每一个独立的小部件都得到了妥善安置;与此同时,每一轮迭代还会不断循环往复地优化完善现有布局方案以适应不同的设备环境变化需求[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值