2

据说调用invalidate()时会调用onDraw()。但是,当我查看 android 源代码时。我没有找到在 invalidate() 中调用 onDraw() 的位置。所以我仍然对如何为视图调用 onDraw() 方法感到困惑。谁能帮我解决这个问题?

4

6 回答 6

8

Invalidate不会onDraw()直接打电话。它为系统安排了一次绘制通道,表示视图需要在未来的某个时间点进行绘制,这通常几乎是立即进行。如果 UI 线程被阻塞,它可能需要一些时间。

于 2013-07-10T17:22:58.160 回答
8

绘画

通过遍历树并渲染与无效区域相交的每个视图来处理绘图。因为树是按顺序遍历的,这意味着父母将在他们的孩子之前(即之后)绘制,兄弟姐妹按照它们在树中出现的顺序绘制。如果您为 View 设置了背景可绘制对象,则 View 将在回调其 onDraw() 方法之前为您绘制它。请注意,框架不会绘制不在无效区域中的视图。要强制绘制视图,请调用invalidate().

使整个视图无效。如果视图可见,onDraw(android.graphics.Canvas) 将在未来的某个时间点被调用。这必须从 UI 线程调用。要从非 UI 线程调用,请调用 postInvalidate()

10340    public void invalidate() {
10341        invalidate(true);
10342    }

来源

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.2.2_r1/android/view/View.java#View.invalidate%28boolean%29

这是 invalidate() 工作实际发生的地方。完整的 invalidate() 会导致绘图缓存失效,但可以在 invalidateCache 设置为 false 的情况下调用此函数,以在不需要它的情况下跳过该失效步骤(例如,与相同的内容)。

参数:

invalidateCache 此视图的绘图缓存是否也应失效。这对于完全无效通常是正确的,但如果视图的内容或尺寸没有改变,则可以设置为 false。

10354
10355    void invalidate(boolean invalidateCache) {
10356        if (skipInvalidate()) {
10357            return;
10358        }
10359        if ((mPrivateFlags & (PFLAG_DRAWN | PFLAG_HAS_BOUNDS)) == (PFLAG_DRAWN | PFLAG_HAS_BOUNDS) ||
10360                (invalidateCache && (mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == PFLAG_DRAWING_CACHE_VALID) ||
10361                (mPrivateFlags & PFLAG_INVALIDATED) != PFLAG_INVALIDATED || isOpaque() != mLastIsOpaque) {
10362            mLastIsOpaque = isOpaque();
10363            mPrivateFlags &= ~PFLAG_DRAWN;
10364            mPrivateFlags |= PFLAG_DIRTY;
10365            if (invalidateCache) {
10366                mPrivateFlags |= PFLAG_INVALIDATED;
10367                mPrivateFlags &= ~PFLAG_DRAWING_CACHE_VALID;
10368            }
10369            final AttachInfo ai = mAttachInfo;
10370            final ViewParent p = mParent;
10371            //noinspection PointlessBooleanExpression,ConstantConditions
10372            if (!HardwareRenderer.RENDER_DIRTY_REGIONS) {
10373                if (p != null && ai != null && ai.mHardwareAccelerated) {
10374                    // fast-track for GL-enabled applications; just invalidate the whole hierarchy
10375                    // with a null dirty rect, which tells the ViewAncestor to redraw everything
10376                    p.invalidateChild(this, null);
10377                    return;
10378                }
10379            }
10380
10381            if (p != null && ai != null) {
10382                final Rect r = ai.mTmpInvalRect;
10383                r.set(0, 0, mRight - mLeft, mBottom - mTop);
10384                // Don't call invalidate -- we don't want to internally scroll
10385                // our own bounds
10386                p.invalidateChild(this, r);
10387            }
10388        }
10389    }
于 2013-07-10T17:26:36.783 回答
1

我必须调用 setWillNotDraw(false)。ViewGroup 的所有子类默认设置为 true。

于 2014-02-16T17:44:00.317 回答
0

看看这个帖子。这准确地解释了何时调用 onDraw()。

于 2013-07-10T17:25:24.443 回答
0

根据视图 | 安卓开发者

通过遍历树并渲染与无效区域相交的每个视图来处理绘图。因为树是按顺序遍历的,这意味着父母将在他们的孩子之前(即之后)绘制,兄弟姐妹按照它们在树中出现的顺序绘制。如果您为 View 设置了背景可绘制对象,则 View 将在回调其 onDraw() 方法之前为您绘制它。

请注意,框架不会绘制不在无效区域中的视图。

要强制绘制视图,请调用 invalidate()。

这意味着当 UI 线程到达它(无效区域)时,它将为该区域调用 onDraw()。

于 2013-07-10T17:26:06.383 回答
-1

视图的 onDraw() 在以下情况下被调用:

  1. 最初绘制视图
  2. 每当在视图上调用invalidate()
于 2013-07-10T17:22:28.087 回答