博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解析View的getDrawingCache方法
阅读量:5880 次
发布时间:2019-06-19

本文共 11430 字,大约阅读时间需要 38 分钟。

1. View 的getDrawingCache方法

  有时候需要将某个view的内容以图片的方式保存下来,感觉就和截图差不多,可以使用View 的getDrawingCache方法,返回一个Bitmap对象。

2. View的getDrawingCache的具体实现

  查看View的getDrawingCache()方法

/**  * 

Calling this method is equivalent to calling getDrawingCache(false).

* * @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)方法。

/**  * 

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.

* *

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.

* * @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)方法:

/**  * 

Forces the drawing cache to be built if the drawing cache is invalid.

* *

If you call {

@link #buildDrawingCache()} manually without calling * {
@link #setDrawingCacheEnabled(boolean) setDrawingCacheEnabled(true)}, you * should cleanup the cache by calling {
@link #destroyDrawingCache()} afterwards.

* *

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.

* *

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.

* * @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; }

 

转载于:https://www.cnblogs.com/zhangmiao14/p/6772461.html

你可能感兴趣的文章
在odl中怎样实现rpc
查看>>
leetcode 110 Balanced Binary Tree
查看>>
python活用isdigit方法显示系统进程
查看>>
项目开发总结
查看>>
知行合一
查看>>
jmeter插件之jsonpath提取响应结果和做断言
查看>>
发布支持多线程的PowerShell模块 —— MultiThreadTaskRunner
查看>>
Ubuntu ctrl+alt会导致窗口还原的问题
查看>>
第四十期百度技术沙龙笔记整理
查看>>
推荐系统那点事 —— 基于Spark MLlib的特征选择
查看>>
linux 下RTL8723/RTL8188调试记录(命令行)【转】
查看>>
[Contiki系列论文之1]Contiki——为微传感器网络而生的轻量级的、灵活的操作系统...
查看>>
Android 网络编程 记录
查看>>
微软同步发行Windows 10和Windows 10 Mobile系统更新
查看>>
Zeppelin的入门使用系列之使用Zeppelin运行shell命令(二)
查看>>
form表单下的button按钮会自动提交表单的问题
查看>>
那些年追过的......写过的技术博客
查看>>
python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列
查看>>
CSS魔法堂:Transition就这么好玩
查看>>
Golang协程与通道整理
查看>>