解析View的getDrawingCache方法,getdrawingcache

來源:互聯網
上載者:User

解析View的getDrawingCache方法,getdrawingcache
1. View 的getDrawingCache方法

  有時候需要將某個view的內容以圖片的方式儲存下來,感覺就和差不多,可以使用View 的getDrawingCache方法,返回一個Bitmap對象。

2. View的getDrawingCache的具體實現

  查看View的getDrawingCache()方法

/**  * <p>Calling this method is equivalent to calling <code>getDrawingCache(false)</code>.</p>  *  * @return A non-scaled bitmap representing this view or null if cache is disabled.  *  * @see #getDrawingCache(boolean)  */ public Bitmap getDrawingCache() {     return getDrawingCache(false); }

  看代碼繼續調用了getDrawingCache(false)方法,繼續查看getDrawingCache(false)方法。

/**  * <p>Returns the bitmap in which this view drawing is cached. The returned bitmap  * is null when caching is disabled. If caching is enabled and the cache is not ready,  * this method will create it. Calling {@link #draw(android.graphics.Canvas)} will not  * draw from the cache when the cache is enabled. To benefit from the cache, you must  * request the drawing cache by calling this method and draw it on screen if the  * returned bitmap is not null.</p>  *  * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,  * this method will create a bitmap of the same size as this view. Because this bitmap  * will be drawn scaled by the parent ViewGroup, the result on screen might show  * scaling artifacts. To avoid such artifacts, you should call this method by setting  * the auto scaling to true. Doing so, however, will generate a bitmap of a different  * size than the view. This implies that your application must be able to handle this  * size.</p>  *  * @param autoScale Indicates whether the generated bitmap should be scaled based on  *        the current density of the screen when the application is in compatibility  *        mode.  *  * @return A bitmap representing this view or null if cache is disabled.  *  * @see #setDrawingCacheEnabled(boolean)  * @see #isDrawingCacheEnabled()  * @see #buildDrawingCache(boolean)  * @see #destroyDrawingCache()  */ public Bitmap getDrawingCache(boolean autoScale) {     if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {         return null;     }     if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) {         buildDrawingCache(autoScale);     }     return autoScale ? mDrawingCache : mUnscaledDrawingCache; }

  查看getDrawingCache(false)方法,如果該視圖的標誌是WILL_NOT_CACHE_DEAWING(表示該view沒有任何繪圖緩衝)則直接返回null,如果視圖的標誌是DRWING_CACHE_ENABLED(表示該view將自己的繪圖緩衝成一個bitmap),則調用buildDrawingCache(autoScale)方法。

  因為傳遞過來的autoScale為false,則返回的Bitmap是mUnscaledDrawingCache。

  查看buildDrawingCache(autoScale)方法:

/**  * <p>Forces the drawing cache to be built if the drawing cache is invalid.</p>  *  * <p>If you call {@link #buildDrawingCache()} manually without calling  * {@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you  * should cleanup the cache by calling {@link #destroyDrawingCache()} afterwards.</p>  *  * <p>Note about auto scaling in compatibility mode: When auto scaling is not enabled,  * this method will create a bitmap of the same size as this view. Because this bitmap  * will be drawn scaled by the parent ViewGroup, the result on screen might show  * scaling artifacts. To avoid such artifacts, you should call this method by setting  * the auto scaling to true. Doing so, however, will generate a bitmap of a different  * size than the view. This implies that your application must be able to handle this  * size.</p>  *  * <p>You should avoid calling this method when hardware acceleration is enabled. If  * you do not need the drawing cache bitmap, calling this method will increase memory  * usage and cause the view to be rendered in software once, thus negatively impacting  * performance.</p>  *  * @see #getDrawingCache()  * @see #destroyDrawingCache()  */ public void buildDrawingCache(boolean autoScale) {     if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || (autoScale ?             mDrawingCache == null : mUnscaledDrawingCache == null)) {         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {             Trace.traceBegin(Trace.TRACE_TAG_VIEW,                     "buildDrawingCache/SW Layer for " + getClass().getSimpleName());         }         try {             buildDrawingCacheImpl(autoScale);         } finally {             Trace.traceEnd(Trace.TRACE_TAG_VIEW);         }     } }

  如果mPrivateFlags與PFLAG_DRAWING_CACHE_VALID與運算為0,或者mUnscaledDrawingCache為null,則調用buildDrawingCacheImpl(autoScale)方法。

查看buildDrawingCacheImpl(autoScale)方法,

/**  * private, internal implementation of buildDrawingCache, used to enable tracing  */ private void buildDrawingCacheImpl(boolean autoScale) {    mCachingFailed = false;    int width = mRight - mLeft;    int height = mBottom - mTop;    final AttachInfo attachInfo = mAttachInfo;    final boolean scalingRequired = attachInfo != null && attachInfo.mScalingRequired;    if (autoScale && scalingRequired) {        width = (int) ((width * attachInfo.mApplicationScale) + 0.5f);        height = (int) ((height * attachInfo.mApplicationScale) + 0.5f);    }    final int drawingCacheBackgroundColor = mDrawingCacheBackgroundColor;    final boolean opaque = drawingCacheBackgroundColor != 0 || isOpaque();    final boolean use32BitCache = attachInfo != null && attachInfo.mUse32BitDrawingCache;    final long projectedBitmapSize = width * height * (opaque && !use32BitCache ? 2 : 4);    final long drawingCacheSize =            ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize();    if (width <= 0 || height <= 0 || projectedBitmapSize > drawingCacheSize) {        if (width > 0 && height > 0) {            Log.w(VIEW_LOG_TAG, getClass().getSimpleName() + " not displayed because it is"                    + " too large to fit into a software layer (or drawing cache), needs "                    + projectedBitmapSize + " bytes, only "                    + drawingCacheSize + " available");        }        destroyDrawingCache();        mCachingFailed = true;        return;    }    boolean clear = true;    Bitmap bitmap = autoScale ? mDrawingCache : mUnscaledDrawingCache;    if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {        Bitmap.Config quality;        if (!opaque) {            // Never pick ARGB_4444 because it looks awful            // Keep the DRAWING_CACHE_QUALITY_LOW flag just in case            switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {                case DRAWING_CACHE_QUALITY_AUTO:                case DRAWING_CACHE_QUALITY_LOW:                case DRAWING_CACHE_QUALITY_HIGH:                default:                    quality = Bitmap.Config.ARGB_8888;                    break;            }        } else {            // Optimization for translucent windows            // If the window is translucent, use a 32 bits bitmap to benefit from memcpy()            quality = use32BitCache ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;        }        // Try to cleanup memory        if (bitmap != null) bitmap.recycle();        try {            bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),                    width, height, quality);            bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);            if (autoScale) {                mDrawingCache = bitmap;            } else {                mUnscaledDrawingCache = bitmap;            }            if (opaque && use32BitCache) bitmap.setHasAlpha(false);        } catch (OutOfMemoryError e) {            // If there is not enough memory to create the bitmap cache, just            // ignore the issue as bitmap caches are not required to draw the            // view hierarchy            if (autoScale) {                mDrawingCache = null;            } else {                mUnscaledDrawingCache = null;            }            mCachingFailed = true;            return;        }        clear = drawingCacheBackgroundColor != 0;    }    Canvas canvas;    if (attachInfo != null) {        canvas = attachInfo.mCanvas;        if (canvas == null) {            canvas = new Canvas();        }        canvas.setBitmap(bitmap);        // Temporarily clobber the cached Canvas in case one of our children        // is also using a drawing cache. Without this, the children would        // steal the canvas by attaching their own bitmap to it and bad, bad        // thing would happen (invisible views, corrupted drawings, etc.)        attachInfo.mCanvas = null;    } else {        // This case should hopefully never or seldom happen        canvas = new Canvas(bitmap);    }    if (clear) {        bitmap.eraseColor(drawingCacheBackgroundColor);    }    computeScroll();    final int restoreCount = canvas.save();    if (autoScale && scalingRequired) {        final float scale = attachInfo.mApplicationScale;        canvas.scale(scale, scale);    }    canvas.translate(-mScrollX, -mScrollY);    mPrivateFlags |= PFLAG_DRAWN;    if (mAttachInfo == null || !mAttachInfo.mHardwareAccelerated ||            mLayerType != LAYER_TYPE_NONE) {        mPrivateFlags |= PFLAG_DRAWING_CACHE_VALID;    }    // Fast path for layouts with no backgrounds    if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {        mPrivateFlags &= ~PFLAG_DIRTY_MASK;        dispatchDraw(canvas);        if (mOverlay != null && !mOverlay.isEmpty()) {            mOverlay.getOverlayView().draw(canvas);        }    } else {        draw(canvas);    }    canvas.restoreToCount(restoreCount);    canvas.setBitmap(null);    if (attachInfo != null) {        // Restore the cached Canvas for our siblings        attachInfo.mCanvas = canvas;    }}


  代碼中AttachInfo類是串連到他的父window時給view的一組資訊。

  參數autoScale的值為false,可以忽略一些if判斷語句。

  方法分為三步:

    第一步:得到view的寬width與高height。

int width = mRight - mLeft;int height = mBottom - mTop;

    第二步,產生bitmap。

bitmap = Bitmap.createBitmap(mResources.getDisplayMetrics(),width, height, quality);bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);

  use32BitCache資料代表的是view是否需要使用32-bit繪圖緩衝,當window為半透明的時候,使用32位繪圖緩衝。

    第三步,繪製canvas。

canvas.setBitmap(bitmap);canvas = new Canvas(bitmap);draw(canvas);
3. 自訂view的getDrawingCache方法

  有時候自訂的view雖然繼承View,但是調用View的getDrawingCache()方法的時候會出現一些問題,返回的bitmap為null,這個時候就需要自己寫一個getDrawingCache方法,可以參考buildDrawingCacheImpl方法去實現,實現如下:

public Bitmap getBitmap() {     Bitmap bitmap = null;     int width = getRight() - getLeft();     int height = getBottom() - getTop();     final boolean opaque = getDrawingCacheBackgroundColor() != 0 || isOpaque();     Bitmap.Config quality;     if (!opaque) {         switch (getDrawingCacheQuality()) {             case DRAWING_CACHE_QUALITY_AUTO:             case DRAWING_CACHE_QUALITY_LOW:             case DRAWING_CACHE_QUALITY_HIGH:             default:                 quality = Bitmap.Config.ARGB_8888;                 break;         }     } else {         quality = Bitmap.Config.RGB_565;     }     if (opaque) bitmap.setHasAlpha(false);     bitmap = Bitmap.createBitmap(getResources().getDisplayMetrics(),             width, height, quality);     bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);     boolean clear = getDrawingCacheBackgroundColor() != 0;     Canvas canvas = new Canvas(bitmap);     if (clear) {         bitmap.eraseColor(getDrawingCacheBackgroundColor());     }     computeScroll();     final int restoreCount = canvas.save();     canvas.translate(-getScrollX(), -getScrollY());     draw(canvas);     canvas.restoreToCount(restoreCount);     canvas.setBitmap(null);     return bitmap; }

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.