android自定義view-繪製順序及相關原理

yangxi_001發表於2013-12-25

Android系統中要自定義view,首先需要了解Android的view載入機制。主要有三個方法:

1、onMeasure()     //計算出view自身大小
2、onLayout()     //僅在ViewGroup中,用來為子view指定位置
3、onDraw()      //view繪製內容

那麼系統能讓我們在onDraw()能夠繪製些什麼呢,檢視View.draw()原始碼發現

[java] view plaincopy
  1. /** 
  2.    * Manually render this view (and all of its children) to the given Canvas. 
  3.    * The view must have already done a full layout before this function is 
  4.    * called.  When implementing a view, implement 
  5.    * {@link #onDraw(android.graphics.Canvas)} instead of overriding this method. 
  6.    * If you do need to override this method, call the superclass version. 
  7.    * 
  8.    * @param canvas The Canvas to which the View is rendered. 
  9.    */  
  10.   public void draw(Canvas canvas) {  
  11.       if (ViewDebug.TRACE_HIERARCHY) {  
  12.           ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);  
  13.       }  
  14.   
  15.       final int privateFlags = mPrivateFlags;  
  16.       final boolean dirtyOpaque = (privateFlags & DIRTY_MASK) == DIRTY_OPAQUE &&  
  17.               (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState);  
  18.       mPrivateFlags = (privateFlags & ~DIRTY_MASK) | DRAWN;  
  19.   
  20.       /* 
  21.        * Draw traversal performs several drawing steps which must be executed 
  22.        * in the appropriate order: 
  23.        * 
  24.        *      1. Draw the background 
  25.        *      2. If necessary, save the canvas' layers to prepare for fading 
  26.        *      3. Draw view's content 
  27.        *      4. Draw children 
  28.        *      5. If necessary, draw the fading edges and restore layers 
  29.        *      6. Draw decorations (scrollbars for instance) 
  30.        */  
  31.   
  32.       // Step 1, draw the background, if needed  
  33.       int saveCount;  
  34.   
  35.       if (!dirtyOpaque) {  
  36.           final Drawable background = mBGDrawable;  
  37.           if (background != null) {  
  38.               final int scrollX = mScrollX;  
  39.               final int scrollY = mScrollY;  
  40.   
  41.               if (mBackgroundSizeChanged) {  
  42.                   background.setBounds(00,  mRight - mLeft, mBottom - mTop);  
  43.                   mBackgroundSizeChanged = false;  
  44.               }  
  45.   
  46.               if ((scrollX | scrollY) == 0) {  
  47.                   background.draw(canvas);  
  48.               } else {  
  49.                   canvas.translate(scrollX, scrollY);  
  50.                   background.draw(canvas);  
  51.                   canvas.translate(-scrollX, -scrollY);  
  52.               }  
  53.           }  
  54.       }  
  55.   
  56.       // skip step 2 & 5 if possible (common case)  
  57.       final int viewFlags = mViewFlags;  
  58.       boolean horizontalEdges = (viewFlags & FADING_EDGE_HORIZONTAL) != 0;  
  59.       boolean verticalEdges = (viewFlags & FADING_EDGE_VERTICAL) != 0;  
  60.       if (!verticalEdges && !horizontalEdges) {  
  61.           // Step 3, draw the content  
  62.           if (!dirtyOpaque) onDraw(canvas);  
  63.   
  64.           // Step 4, draw the children  
  65.           dispatchDraw(canvas);  
  66.   
  67.           // Step 6, draw decorations (scrollbars)  
  68.           onDrawScrollBars(canvas);  
  69.   
  70.           // we're done...  
  71.           return;  
  72.       }  
  73.   
  74.       /* 
  75.        * Here we do the full fledged routine... 
  76.        * (this is an uncommon case where speed matters less, 
  77.        * this is why we repeat some of the tests that have been 
  78.        * done above) 
  79.        */  
  80.   
  81.       boolean drawTop = false;  
  82.       boolean drawBottom = false;  
  83.       boolean drawLeft = false;  
  84.       boolean drawRight = false;  
  85.   
  86.       float topFadeStrength = 0.0f;  
  87.       float bottomFadeStrength = 0.0f;  
  88.       float leftFadeStrength = 0.0f;  
  89.       float rightFadeStrength = 0.0f;  
  90.   
  91.       // Step 2, save the canvas' layers  
  92.       int paddingLeft = mPaddingLeft;  
  93.   
  94.       final boolean offsetRequired = isPaddingOffsetRequired();  
  95.       if (offsetRequired) {  
  96.           paddingLeft += getLeftPaddingOffset();  
  97.       }  
  98.   
  99.       int left = mScrollX + paddingLeft;  
  100.       int right = left + mRight - mLeft - mPaddingRight - paddingLeft;  
  101.       int top = mScrollY + getFadeTop(offsetRequired);  
  102.       int bottom = top + getFadeHeight(offsetRequired);  
  103.   
  104.       if (offsetRequired) {  
  105.           right += getRightPaddingOffset();  
  106.           bottom += getBottomPaddingOffset();  
  107.       }  
  108.   
  109.       final ScrollabilityCache scrollabilityCache = mScrollCache;  
  110.       final float fadeHeight = scrollabilityCache.fadingEdgeLength;          
  111.       int length = (int) fadeHeight;  
  112.   
  113.       // clip the fade length if top and bottom fades overlap  
  114.       // overlapping fades produce odd-looking artifacts  
  115.       if (verticalEdges && (top + length > bottom - length)) {  
  116.           length = (bottom - top) / 2;  
  117.       }  
  118.   
  119.       // also clip horizontal fades if necessary  
  120.       if (horizontalEdges && (left + length > right - length)) {  
  121.           length = (right - left) / 2;  
  122.       }  
  123.   
  124.       if (verticalEdges) {  
  125.           topFadeStrength = Math.max(0.0f, Math.min(1.0f, getTopFadingEdgeStrength()));  
  126.           drawTop = topFadeStrength * fadeHeight > 1.0f;  
  127.           bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, getBottomFadingEdgeStrength()));  
  128.           drawBottom = bottomFadeStrength * fadeHeight > 1.0f;  
  129.       }  
  130.   
  131.       if (horizontalEdges) {  
  132.           leftFadeStrength = Math.max(0.0f, Math.min(1.0f, getLeftFadingEdgeStrength()));  
  133.           drawLeft = leftFadeStrength * fadeHeight > 1.0f;  
  134.           rightFadeStrength = Math.max(0.0f, Math.min(1.0f, getRightFadingEdgeStrength()));  
  135.           drawRight = rightFadeStrength * fadeHeight > 1.0f;  
  136.       }  
  137.   
  138.       saveCount = canvas.getSaveCount();  
  139.   
  140.       int solidColor = getSolidColor();  
  141.       if (solidColor == 0) {  
  142.           final int flags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;  
  143.   
  144.           if (drawTop) {  
  145.               canvas.saveLayer(left, top, right, top + length, null, flags);  
  146.           }  
  147.   
  148.           if (drawBottom) {  
  149.               canvas.saveLayer(left, bottom - length, right, bottom, null, flags);  
  150.           }  
  151.   
  152.           if (drawLeft) {  
  153.               canvas.saveLayer(left, top, left + length, bottom, null, flags);  
  154.           }  
  155.   
  156.           if (drawRight) {  
  157.               canvas.saveLayer(right - length, top, right, bottom, null, flags);  
  158.           }  
  159.       } else {  
  160.           scrollabilityCache.setFadeColor(solidColor);  
  161.       }  
  162.   
  163.       // Step 3, draw the content  
  164.       if (!dirtyOpaque) onDraw(canvas);  
  165.   
  166.       // Step 4, draw the children  
  167.       dispatchDraw(canvas);  
  168.   
  169.       // Step 5, draw the fade effect and restore layers  
  170.       final Paint p = scrollabilityCache.paint;  
  171.       final Matrix matrix = scrollabilityCache.matrix;  
  172.       final Shader fade = scrollabilityCache.shader;  
  173.   
  174.       if (drawTop) {  
  175.           matrix.setScale(1, fadeHeight * topFadeStrength);  
  176.           matrix.postTranslate(left, top);  
  177.           fade.setLocalMatrix(matrix);  
  178.           canvas.drawRect(left, top, right, top + length, p);  
  179.       }  
  180.   
  181.       if (drawBottom) {  
  182.           matrix.setScale(1, fadeHeight * bottomFadeStrength);  
  183.           matrix.postRotate(180);  
  184.           matrix.postTranslate(left, bottom);  
  185.           fade.setLocalMatrix(matrix);  
  186.           canvas.drawRect(left, bottom - length, right, bottom, p);  
  187.       }  
  188.   
  189.       if (drawLeft) {  
  190.           matrix.setScale(1, fadeHeight * leftFadeStrength);  
  191.           matrix.postRotate(-90);  
  192.           matrix.postTranslate(left, top);  
  193.           fade.setLocalMatrix(matrix);  
  194.           canvas.drawRect(left, top, left + length, bottom, p);  
  195.       }  
  196.   
  197.       if (drawRight) {  
  198.           matrix.setScale(1, fadeHeight * rightFadeStrength);  
  199.           matrix.postRotate(90);  
  200.           matrix.postTranslate(right, top);  
  201.           fade.setLocalMatrix(matrix);  
  202.           canvas.drawRect(right - length, top, right, bottom, p);  
  203.       }  
  204.   
  205.       canvas.restoreToCount(saveCount);  
  206.   
  207.       // Step 6, draw decorations (scrollbars)  
  208.       onDrawScrollBars(canvas);  
  209.   }  

下面根據原始碼中的相關說明,進一步分析控制元件的繪製操作及順序:

[java] view plaincopy
  1. /* 
  2.  * Draw traversal performs several drawing steps which must be executed 
  3.  * in the appropriate order: 
  4.  * 
  5.  *  1. Draw the background  (繪製控制元件設定的背景,系統已在view.draw()中繪製,只要在xml中指定背景即可) 
  6.  *  2. If necessary, save the canvas' layers to prepare for fading   
  7.  *  3. Draw view's content  (可以重寫, onDraw(canvas);) 
  8.  *  4. Draw children      (可重寫,用來分發canvas到子控制元件,具體看ViewGroup。對應方法dispatchDraw(canvas);此方法依次呼叫了子控制元件的draw()方法) 
  9.  *  5. If necessary, draw the fading edges and restore layers (繪製控制元件四周的陰影漸變效果) 
  10.  *  6. Draw decorations (scrollbars for instance) (用來繪製滾動條,對應方法onDrawScrollBars(canvas);。 
  11.  *      onDrawHorizontalScrollBar()和onDrawVerticalScrollBar()被隱藏了無法重寫,也許有其他方法重寫滾動條) 
  12.  */  


轉載自:http://orgcent.com/android-custom-view-draw-mechanism/ | 蘿蔔白菜的部落格

相關文章