本篇終于來到了View的三大流程的最后一個流程了,本次會帶著大家探究一下View的 performDraw()
究竟是如何工作的。
先看performDraw()
由于 performDraw()
的代碼并不多,那我們就先看看它的實現吧!
private void performDraw() { if (mAttachInfo.mDisplayState == Display.STATE_OFF amp;amp; !mReportNextDraw) { return; } final boolean fullRedrawNeeded = mFullRedrawNeeded; mFullRedrawNeeded = false; mIsDrawing = true; Trace.traceBegin(Trace.TRACE_TAG_VIEW, quot;drawquot;); try { // 1. 調用繪制方法 draw(fullRedrawNeeded); } finally { mIsDrawing = false; Trace.traceEnd(Trace.TRACE_TAG_VIEW); } // For whatever reason we didn't create a HardwareRenderer, end any // hardware animations that are now dangling if (mAttachInfo.mPendingAnimatingRenderNodes != null) { final int count = mAttachInfo.mPendingAnimatingRenderNodes.size(); for (int i = 0; i lt; count; i ) { mAttachInfo.mPendingAnimatingRenderNodes.get(i).endAllAnimators(); } mAttachInfo.mPendingAnimatingRenderNodes.clear(); } if (mReportNextDraw) { mReportNextDraw = false; if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.fence(); } if (LOCAL_LOGV) { Log.v(TAG, quot;FINISHED DRAWING: quot; mWindowAttributes.getTitle()); } if (mSurfaceHolder != null amp;amp; mSurface.isValid()) { mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder); SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks(); if (callbacks != null) { for (SurfaceHolder.Callback c : callbacks) { if (c instanceof SurfaceHolder.Callback2) { ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded( mSurfaceHolder); } } } } try { mWindowSession.finishDrawing(mWindow); } catch (RemoteException e) { } } }
從上面的代碼可以看出,View的繪制流程并不復雜,其中最主要的就是調用了 draw()
方法。那我們來看看 draw()
方法的代碼。我們只探究繪制流程的基本過程,所以我只把關鍵的代碼貼出。其實其中關鍵的代碼也就那么一句。
private void draw(boolean fullRedrawNeeded) { ...... mAttachInfo.mTreeObserver.dispatchOnDraw(); ...... }
android
就是通過上面的那句代碼將繪制的任務分發到 view tree
中的每一個View中。那我們再來看看這個 ViewTreeObserver
對象是什么。下面是該類的官方注釋聲明。
/** * A view tree observer is used to register listeners that can be notified of global * changes in the view tree. Such global events include, but are not limited to, * layout of the whole tree, beginning of the drawing pass, touch mode change.... * * A ViewTreeObserver should never be instantiated by applications as it is provided * by the views hierarchy. Refer to {@link android.view.View#getViewTreeObserver()} * for more information. */ public final class ViewTreeObserver
ViewTreeObserver
用于注冊關于 view tree
的各種事件的監聽器,例如繪制事件,布局事件,滾動事件等等。 View
的繪制過程就是通過 ViewTreeObserver
注冊監聽來進行事件分發的。
/** * Interface definition for a callback to be invoked when the view tree is about to be drawn. */ public interface OnDrawListener { /** * lt;pgt;Callback method to be invoked when the view tree is about to be drawn. At this point, * views cannot be modified in any way.lt;/pgt; * * lt;pgt;Unlike with {@link OnPreDrawListener}, this method cannot be used to cancel the * current drawing pass.lt;/pgt; * * lt;pgt;An {@link OnDrawListener} listener lt;stronggt;cannot be added or removedlt;/stronggt; * from this method.lt;/pgt; * * @see android.view.View#onMeasure * @see android.view.View#onLayout * @see android.view.View#onDraw */ public void onDraw(); } /** * Notifies registered listeners that the drawing pass is about to start. */ public final void dispatchOnDraw() { if (mOnDrawListeners != null) { final ArrayListlt;OnDrawListenergt; listeners = mOnDrawListeners; int numListeners = listeners.size(); for (int i = 0; i lt; numListeners; i) { listeners.get(i).onDraw(); } } }
通過監聽器來調用 view tree
中的各個View的 onDraw()
方法。
View的draw()
到這里我們基本的 performDraw()
的流程已經清楚了。現在我們再回到 View
類中來看看它的 draw()
是如何實現的。下面就是 View
中的 draw()
方法的代碼。
/** * Manually render this view (and all of its children) to the given Canvas. * The view must have already done a full layout before this function is * called. When implementing a view, implement * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. * If you do need to override this method, call the superclass version. * * @param canvas The Canvas to which the View is rendered. */ @CallSuper public void draw(Canvas canvas) { final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags amp; PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE amp;amp; (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); mPrivateFlags = (privateFlags amp; ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; /* * Draw traversal performs several drawing steps which must be executed * in the appropriate order: * * 1. Draw the background * 2. If necessary, save the canvas' layers to prepare for fading * 3. Draw view's content * 4. Draw children * 5. If necessary, draw the fading edges and restore layers * 6. Draw decorations (scrollbars for instance) */ // Step 1, draw the background, if needed int saveCount; if (!dirtyOpaque) { drawBackground(canvas); } // skip step 2 amp; 5 if possible (common case) final int viewFlags = mViewFlags; boolean horizontalEdges = (viewFlags amp; FADING_EDGE_HORIZONTAL) != 0; boolean verticalEdges = (viewFlags amp; FADING_EDGE_VERTICAL) != 0; if (!verticalEdges amp;amp; !horizontalEdges) { // Step 3, draw the content if (!dirtyOpaque) onDraw(canvas); // Step 4, draw the children dispatchDraw(canvas); // Overlay is part of the content and draws beneath Foreground if (mOverlay != null amp;amp; !mOverlay.isEmpty()) { mOverlay.getOverlayView().dispatchDraw(canvas); } // Step 6, draw decorations (foreground, scrollbars) onDrawForeground(canvas); // we're done... return; }
代碼中的注釋說了,一次繪制的流程必須有序的執行下面的六步的操作:
- 繪制背景
- 必要時保存
canvas
層來為View的fading準備 - 繪制View的內容
- 繪制View的孩子
- 必要時繪制View的fading并且恢復第2步保存的
canvas
層 - 繪制View的decoration,例如前景和滾動條
以上的就是View的繪制步驟。當我們需要繼承一個View并需要對View的繪制進行自定義時,我們只需要完成第3步就可以了,其他的步驟 View
已經幫我們完成了。我們只需重寫View的 onDraw()
方法即可。
總結
View
的基本繪制過程算是比較簡單吧,按照慣例我們也用張圖片來進行總結。
Tags: 安卓開發
文章來源:http://www.jianshu.com/p/bd9780a967a9