View转换为Bitmap及getDrawingCache
View组件显示的内容可以通过cache机制保存为bitmap, 使用到的api有
void setDrawingCacheEnabled(boolean flag),
Bitmap getDrawingCache(boolean autoScale),
void buildDrawingCache(boolean autoScale),
void destroyDrawingCache()
- 我们要获取它的cache先要通过setDrawingCacheEnable方法把cache开启,
- 然后再调用getDrawingCache方法就可以获得view的cache图片了。
- buildDrawingCache方法可以不用调用,因为调用getDrawingCache方法时,若果cache没有建立,系统会自动调用buildDrawingCache方法生成cache。若果要更新cache, 必须要调用destoryDrawingCache方法把旧的cache销毁,才能建立新的。
- 当调用setDrawingCacheEnabled方法设置为false, 系统也会自动把原来的cache销毁。
android 为了提高滚动等各方面的绘制速度,可以为每一个view建立一个缓存,使用 View.buildDrawingCache为自己的view 建立相应的缓存,
这个所谓的缓存,实际上就是一个Bitmap对象。只是 这个 bitmap 对象可以有多种格式而已,如
Bitmap.Config.ARGB_8888;
Bitmap.Config.ARGB_4444;
Bitmap.Config.RGB_565;
默认的格式是Bitmap.Config.ARGB_8888.,但大多数嵌入式设备使用的显示格式都是Bitmap.Config.RGB_565. 对于后者, 并没有
alpha 值,所以绘制的时候不需要计算alpha合成,速递当让快些。其次,RGB_565可以直接使用优化了的memcopy函数,效率相对高出许多。
view的getDrawingCache获得数据始终为null
setDrawingCacheEnabled
public void setDrawingCacheEnabled(boolean enabled) {
setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
}
DRAWING_CACHE_ENABLED是否支持设置
先看getDrawingCache的源码
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 == null ? null : mDrawingCache.get()) :
(mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get());
}
1) (mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING 这个值为true
2) (mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED
如果 false,buildDrawingCache没执行
3) buildDrawingCache执行失败
这些在源码中都可以看到,在获得缓存数据的时候,跟背景色(drawingCacheBackgroundColor),透明度isOpaque,use32BitCache这些有关系,看是细看这些东西都是表面的,是系统在buildDrawingCache的时候,根据View或都系统设置而来的;有些属性是不能更改的;这样一来当一个固定大小的View在不同的设备上生成的图片就可能有所不同,我同事这边存在的问题就是,设置View的固定大小为1360*768,而我View转换为Bitmap及getDrawingCache的设备分辨率为1024*600,而源码里可以看到这样代码:
if (width <= 0 || height <= 0 ||
// Projected bitmap size in bytes
(width * height * (opaque && !use32BitCache ? 2 : 4) >
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
destroyDrawingCache();
mCachingFailed = true;
return;
}
当我们在buildDrawingCache的时候,系统给了我们默认最大的DrawingCacheSize为屏幕宽*高*4;而我的View的CacheSize大小超过了某些设备默认值,就会导致获得为空;开始想着用反射的方法去改变这些属性,或者设置背景颜色来改变图片质量,这样一来CacheSize大小 就可能会变小,但是这样始终不能达到效果;
最终解决方案:
查看系统buildDrawingCache方法可以看到:
public void buildDrawingCache(boolean autoScale) {
//如果没有buildDrawingCache,则执行
if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
(mDrawingCache == null || mDrawingCache.get() == null) :
(mUnscaledDrawingCache == null || mUnscaledDrawingCache.get() == null))) { if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
}
if (Config.DEBUG && ViewDebug.profileDrawing) {
EventLog.writeEvent(60002, hashCode());
} 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 translucentWindow = attachInfo != null && attachInfo.mTranslucentWindow;
//不满足这些条件不执行
if (width <= 0 || height <= 0 ||
// Projected bitmap size in bytes
(width * height * (opaque && !translucentWindow ? 2 : 4) >
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
destroyDrawingCache();
return;
}
boolean clear = true;
Bitmap bitmap = autoScale ? (mDrawingCache == null ? null : mDrawingCache.get()) :
(mUnscaledDrawingCache == null ? null : mUnscaledDrawingCache.get()); if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) {
Bitmap.Config quality;
if (!opaque) {
switch (mViewFlags & DRAWING_CACHE_QUALITY_MASK) {
case DRAWING_CACHE_QUALITY_AUTO:
quality = Bitmap.Config.ARGB_8888;
break;
case DRAWING_CACHE_QUALITY_LOW:
quality = Bitmap.Config.ARGB_4444;
break;
case DRAWING_CACHE_QUALITY_HIGH:
quality = Bitmap.Config.ARGB_8888;
break;
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 = translucentWindow ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
} // Try to cleanup memory
if (bitmap != null) bitmap.recycle(); try {
bitmap = Bitmap.createBitmap(width, height, quality);
bitmap.setDensity(getResources().getDisplayMetrics().densityDpi);
if (autoScale) {
mDrawingCache = new SoftReference<Bitmap>(bitmap);
} else {
mUnscaledDrawingCache = new SoftReference<Bitmap>(bitmap);
}
if (opaque && translucentWindow) 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;
}
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 |= DRAWN;
mPrivateFlags |= DRAWING_CACHE_VALID; // Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
if (ViewDebug.TRACE_HIERARCHY) {
ViewDebug.trace(this, ViewDebug.HierarchyTraceType.DRAW);
}
mPrivateFlags &= ~DIRTY_MASK;
dispatchDraw(canvas);
} else {
draw(canvas);
} canvas.restoreToCount(restoreCount); if (attachInfo != null) {
// Restore the cached Canvas for our siblings
attachInfo.mCanvas = canvas;
}
}
}
安卓提供了方法,这个方法没有提供一个外部访问方法
/**
* Create a snapshot of the view into a bitmap. We should probably make
* some form of this public, but should think about the API.
*/
Bitmap createSnapshot(Bitmap.Config quality, int backgroundColor, boolean skipChildren) {
int width = mRight - mLeft;
int height = mBottom - mTop; final AttachInfo attachInfo = mAttachInfo;
final float scale = attachInfo != null ? attachInfo.mApplicationScale : 1.0f;
width = (int) ((width * scale) + 0.5f);
height = (int) ((height * scale) + 0.5f); Bitmap bitmap = Bitmap.createBitmap(width > 0 ? width : 1, height > 0 ? height : 1, quality);
if (bitmap == null) {
throw new OutOfMemoryError();
} bitmap.setDensity(getResources().getDisplayMetrics().densityDpi); 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
// things would happen (invisible views, corrupted drawings, etc.)
attachInfo.mCanvas = null;
} else {
// This case should hopefully never or seldom happen
canvas = new Canvas(bitmap);
} if ((backgroundColor & 0xff000000) != 0) {
bitmap.eraseColor(backgroundColor);
} computeScroll();
final int restoreCount = canvas.save();
canvas.scale(scale, scale);
canvas.translate(-mScrollX, -mScrollY); // Temporarily remove the dirty mask
int flags = mPrivateFlags;
mPrivateFlags &= ~DIRTY_MASK; // Fast path for layouts with no backgrounds
if ((mPrivateFlags & SKIP_DRAW) == SKIP_DRAW) {
dispatchDraw(canvas);
} else {
draw(canvas);
} mPrivateFlags = flags; canvas.restoreToCount(restoreCount); if (attachInfo != null) {
// Restore the cached Canvas for our siblings
attachInfo.mCanvas = canvas;
} return bitmap;
}
public static Bitmap getViewBitmap(View v) {
v.clearFocus();
v.setPressed(false);
boolean willNotCache = v.willNotCacheDrawing();
v.setWillNotCacheDrawing(false);
// Reset the drawing cache background color to fully transparent
// for the duration of this operation
int color = v.getDrawingCacheBackgroundColor();
v.setDrawingCacheBackgroundColor(0);
if (color != 0) {
v.destroyDrawingCache();
}
v.buildDrawingCache();
Bitmap cacheBitmap = v.getDrawingCache();
if (cacheBitmap == null) {
return null;
}
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
v.destroyDrawingCache();
v.setWillNotCacheDrawing(willNotCache);
v.setDrawingCacheBackgroundColor(color);
return bitmap;
}
View转换为Bitmap及getDrawingCache的更多相关文章
- Android中View转换为Bitmap及getDrawingCache=null的解决方法
1.前言 Android中经常会遇到把View转换为Bitmap的情形,比如,对整个屏幕视图进行截屏并生成图片:Coverflow中需要把一页一 页的view转换为Bitmap.以便实现复杂的图形效果 ...
- 获取View的截图-将View转换为Bitmap对象
开发中,有时候需要获取View的截图来做动画来达到动画流程的目的 原理:将View的内容画到一个Bitmap画布上,然后取出 下面封装了一个从View生成Bitmap的工具类 /** * 将View转 ...
- android view 转Bitmap 生成截图
文章链接:https://mp.weixin.qq.com/s/FQmYfT-KYiDbp-0HzK_Hpw 项目中经常会用到分享的功能,有分享链接也有分享图片,其中分享图片有的需要移动端对屏幕内容进 ...
- 读取sd卡下图片,由图片路径转换为bitmap
public Bitmap convertToBitmap(String path, int w, int h) { BitmapFactory.Options opts = ...
- Android,View转换bitmap,bitmap转换drawable
Android View转换Bitmap,Bitmap转换Drawable //测试设置bitmap View view1 = ViewGroup.inflate(context, R.layout. ...
- Universal App图片文件和图片byte[]信息转换为bitmap
1. 打开图片文件并转换为BitmapImage类 首先要做的自然是打开一个图片文件了,可以使用FileOpenPicker来手动选择图片,总之能拿到一个StorageFile都行. //打开图片选择 ...
- Android开发之常用必备工具类图片bitmap转成字符串string与String字符串转换为bitmap图片格式
作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 QQ986945193 博客园主页:http://www.cnblogs.com/mcxiaobing ...
- 将View兑换Bitmap
/** * 中间View保罗转化成Bitmap * */ private Bitmap saveViewBitmap(View view) { // get current view bitmap v ...
- Convert View To Bitmap
public static Bitmap convertViewToBitmap(View view) { view.destroyDrawingCache(); view.measure(View. ...
随机推荐
- python中string和bool的转换
python中字符串"True" 和 "False"转为bool类型时, 不能通过bool(xx)强转. 注意是因为在python中,除了'& ...
- 文件上传框的美化+预览+ajax
1.文件上传基本写法: <input type="file" name="" id="" value="" /&g ...
- java笔试(2)
- python的WeakKeyDictionary类和weakref模块的其他函数
python的WeakKeyDictionary类和weakref模块的其他函数 # -*- coding: utf-8 -*- # @Author : ydf # @Time : 2019/6/13 ...
- Debain install Jupyter
1. install Anaconda https://www.anaconda.com/download/#linux 2. config jupyter $ ipython from notebo ...
- Linq to Object之非延迟标准查询操作符
非延时标准查询操作符是指不具备延时查询特性的标准查询操作符,这些操作符一般用于辅助延时标准查询操作符使用. 1.ToArray操作符 ToArray操作符用于将一个输入序列转换成一个数组. 方法原型: ...
- source in sight 删除工程
用十六进制编辑器打开 "我的文档/Source Insight/Projects/PROJECTS.DB3" 文件 ,找到你要删除的项目路径及名称字符串,用0替换相关位置的数据.
- cadence spb 16.5 破解过程实例和使用感受_赤松子耶_新浪博客
cadence spb 16.5 破解过程实例和使用感受_赤松子耶_新浪博客 Cadence Allegro16.5详细安装具体的步骤 1.下载SPB16.5下来后,点setup.exe,先安装第一项 ...
- [解决问题]ubuntu无法virtualenv创建python虚拟环境的解决
刚有人问我Ubuntu python虚拟环境无法创建问题,报错same file error,防止今后遇到忘记,记录下可能的问题. 1.先在windows上试了下: pip install virtu ...
- 项目积累demo-01
1 搭建Spring-Boot项目 在这里我使用intellij新建spring boot工程: 点击next; 输入Group以及artifact之后.点击next.之后点击web.接着finish ...