android自定義view-繪製順序及相關原理
Android系統中要自定義view,首先需要了解Android的view載入機制。主要有三個方法:
1、onMeasure() //計算出view自身大小
2、onLayout() //僅在ViewGroup中,用來為子view指定位置
3、onDraw() //view繪製內容
那麼系統能讓我們在onDraw()能夠繪製些什麼呢,檢視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.
- */
- public void draw(Canvas canvas) {
- if (ViewDebug.TRACE_HIERARCHY) {
- ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
- }
- final int privateFlags = mPrivateFlags;
- final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&
- (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);
- mPrivateFlags = (privateFlags & ~DIRTY_MASK) | 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) {
- final Drawable background = mBGDrawable;
- if (background != null) {
- final int scrollX = mScrollX;
- final int scrollY = mScrollY;
- if (mBackgroundSizeChanged) {
- background.setBounds(0, 0, mRight - mLeft, mBottom - mTop);
- mBackgroundSizeChanged = false;
- }
- if ((scrollX | scrollY) == 0) {
- background.draw(canvas);
- } else {
- canvas.translate(scrollX, scrollY);
- background.draw(canvas);
- canvas.translate(-scrollX, -scrollY);
- }
- }
- }
- // skip step 2 & 5 if possible (common case)
- final int viewFlags = mViewFlags;
- boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;
- boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;
- if (!verticalEdges && !horizontalEdges) {
- // Step 3, draw the content
- if (!dirtyOpaque) onDraw(canvas);
- // Step 4, draw the children
- dispatchDraw(canvas);
- // Step 6, draw decorations (scrollbars)
- onDrawScrollBars(canvas);
- // we're done...
- return;
- }
- /*
- * Here we do the full fledged routine...
- * (this is an uncommon case where speed matters less,
- * this is why we repeat some of the tests that have been
- * done above)
- */
- boolean drawTop = false;
- boolean drawBottom = false;
- boolean drawLeft = false;
- boolean drawRight = false;
- float topFadeStrength = 0.0f;
- float bottomFadeStrength = 0.0f;
- float leftFadeStrength = 0.0f;
- float rightFadeStrength = 0.0f;
- // Step 2, save the canvas' layers
- int paddingLeft = mPaddingLeft;
- final boolean offsetRequired = isPaddingOffsetRequired();
- if (offsetRequired) {
- paddingLeft += getLeftPaddingOffset();
- }
- int left = mScrollX + paddingLeft;
- int right = left + mRight - mLeft - mPaddingRight - paddingLeft;
- int top = mScrollY + getFadeTop(offsetRequired);
- int bottom = top + getFadeHeight(offsetRequired);
- if (offsetRequired) {
- right += getRightPaddingOffset();
- bottom += getBottomPaddingOffset();
- }
- final ScrollabilityCache scrollabilityCache = mScrollCache;
- final float fadeHeight = scrollabilityCache.fadingEdgeLength;
- int length = (int) fadeHeight;
- // clip the fade length if top and bottom fades overlap
- // overlapping fades produce odd-looking artifacts
- if (verticalEdges && (top + length > bottom - length)) {
- length = (bottom - top) / 2;
- }
- // also clip horizontal fades if necessary
- if (horizontalEdges && (left + length > right - length)) {
- length = (right - left) / 2;
- }
- if (verticalEdges) {
- topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));
- drawTop = topFadeStrength * fadeHeight > 1.0f;
- bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));
- drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
- }
- if (horizontalEdges) {
- leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));
- drawLeft = leftFadeStrength * fadeHeight > 1.0f;
- rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));
- drawRight = rightFadeStrength * fadeHeight > 1.0f;
- }
- saveCount = canvas.getSaveCount();
- int solidColor = getSolidColor();
- if (solidColor == 0) {
- final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
- if (drawTop) {
- canvas.saveLayer(left, top, right, top + length, null, flags);
- }
- if (drawBottom) {
- canvas.saveLayer(left, bottom - length, right, bottom, null, flags);
- }
- if (drawLeft) {
- canvas.saveLayer(left, top, left + length, bottom, null, flags);
- }
- if (drawRight) {
- canvas.saveLayer(right - length, top, right, bottom, null, flags);
- }
- } else {
- scrollabilityCache.setFadeColor(solidColor);
- }
- // Step 3, draw the content
- if (!dirtyOpaque) onDraw(canvas);
- // Step 4, draw the children
- dispatchDraw(canvas);
- // Step 5, draw the fade effect and restore layers
- final Paint p = scrollabilityCache.paint;
- final Matrix matrix = scrollabilityCache.matrix;
- final Shader fade = scrollabilityCache.shader;
- if (drawTop) {
- matrix.setScale(1, fadeHeight * topFadeStrength);
- matrix.postTranslate(left, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, top, right, top + length, p);
- }
- if (drawBottom) {
- matrix.setScale(1, fadeHeight * bottomFadeStrength);
- matrix.postRotate(180);
- matrix.postTranslate(left, bottom);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, bottom - length, right, bottom, p);
- }
- if (drawLeft) {
- matrix.setScale(1, fadeHeight * leftFadeStrength);
- matrix.postRotate(-90);
- matrix.postTranslate(left, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, top, left + length, bottom, p);
- }
- if (drawRight) {
- matrix.setScale(1, fadeHeight * rightFadeStrength);
- matrix.postRotate(90);
- matrix.postTranslate(right, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(right - length, top, right, bottom, p);
- }
- canvas.restoreToCount(saveCount);
- // Step 6, draw decorations (scrollbars)
- onDrawScrollBars(canvas);
- }
下面根據原始碼中的相關說明,進一步分析控制元件的繪製操作及順序:
- /*
- * Draw traversal performs several drawing steps which must be executed
- * in the appropriate order:
- *
- * 1. Draw the background (繪製控制元件設定的背景,系統已在view.draw()中繪製,只要在xml中指定背景即可)
- * 2. If necessary, save the canvas' layers to prepare for fading
- * 3. Draw view's content (可以重寫, onDraw(canvas);)
- * 4. Draw children (可重寫,用來分發canvas到子控制元件,具體看ViewGroup。對應方法dispatchDraw(canvas);此方法依次呼叫了子控制元件的draw()方法)
- * 5. If necessary, draw the fading edges and restore layers (繪製控制元件四周的陰影漸變效果)
- * 6. Draw decorations (scrollbars for instance) (用來繪製滾動條,對應方法onDrawScrollBars(canvas);。
- * onDrawHorizontalScrollBar()和onDrawVerticalScrollBar()被隱藏了無法重寫,也許有其他方法重寫滾動條)
- */
轉載自:http://orgcent.com/android-custom-view-draw-mechanism/ | 蘿蔔白菜的部落格
相關文章
- Android自定義view-自繪ViewAndroidView
- Android自定義View-卷軸AndroidView
- Android UI繪製流程及原理AndroidUI
- Android自定義View之Paint繪製文字和線AndroidViewAI
- 自定義View-波浪動效View
- 自定義View-扭曲動效View
- Flutter自定義繪製(1)- 繪製基礎Flutter
- mysql自定義排序順序語句MySql排序
- 面試官問你 - 自定義View跟繪製流程相關知識點??面試View
- Flutter 自定義繪製 ViewFlutterView
- Flutter自定義繪製Widget初探Flutter
- [Android]多層波紋擴散動畫——自定義View繪製Android動畫View
- 動畫函式的繪製及自定義動畫函式動畫函式
- Django Admin自定義app中模型顯示順序DjangoAPP模型
- Android 自定義Toast及BUGAndroidAST
- Android View繪製原理:繪製流程排程、測算等AndroidView
- Qt繪製自定義箭頭圖元QT
- flutter 用 CustomPaint 繪製自定義圖案FlutterAI
- Android動畫實現繪製原理Android動畫
- 自定義xunit測試用例的執行順序
- iOS探索 KVO原理及自定義iOS
- iOS探索 KVC原理及自定義iOS
- 【Android自定義View】繪圖之文字篇(三)AndroidView繪圖
- 【Android自定義View】繪圖之Path篇(二)AndroidView繪圖
- # 關於select關鍵字語句定義順序# 關於select關鍵字語句執行順序
- Android自定義View之(一)View繪製流程詳解——向原始碼要答案AndroidView原始碼
- python運算子及優先順序順序Python
- adb 埠自定義及原理說明
- flutter 自定義view 繪製曲線統計圖FlutterView
- QT風格(QStyle):繪製一個自定義QComboBoxQT
- Android程式優先順序Android
- [-Flutter 自定義元件-] 蛛網圖+繪製+動畫實踐Flutter元件動畫
- Android Studio3.1.2及Android P相關問題Android
- Android優化——繪製優化之android系統顯示原理(一)Android優化
- 樹的定義及相關術語
- iOS UI繪製原理iOSUI
- canvas lineWidth 繪製原理Canvas
- canvas lineWidth繪製原理Canvas
- webrtc原理及相關api使用邏輯WebAPI