前言
我们经常会用到将一个View转换为Bitmap的情景,比如截屏保存到本地,比如一些动态的实时View为便于观察和记录数据、需要临时生成静态的Bitmap等等。
我们一般都会这样写:
public static Bitmap convertViewToBitmap(View view){
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
一般情况这种是没有问题的,但是view过大的话,就会buildDrawingCache()失败,当然我们getDrawingCache()得到的bitmap就为null了!
原因
那么为什么会出现这种情况呢?我们可以从源码中看到:
buildDrawingCache(boolean autoScale)
—->buildDrawingCacheImpl(boolean autoScale)
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;
}
width和height是所要cache的view绘制的宽度和高度,所以(width * height * (opaque && !translucentWindow ? 2 : 4)
计算的是当前所需要的cache大小。
ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize()得到的是系统所提供的最大的DrawingCache的值。
当所需要的`drawingCache >系统所提供的最大DrawingCache值时,生成Bitmap就会出现问题,此时获取的Bitmap就为null。
解决方案
public static Bitmap convertViewToBitmap(View view){
view.setDrawingCacheEnabled(true);
view.measure(View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
view.setDrawingCacheEnabled(false);
return bitmap;
}
替代方案
从源码中可以看到buildDrawingCache过程貌似就是利用获得View的Canvas然后画到bitmap上,直接返回对应的bitmap,这样一来,就是我们用getDrawingCache获得的bitmap;跟我们直接将View画到bitmap区别不是很大,所以我们可以自己直接画:
public static Bitmap convertViewToBitmap(View view) {
Bitmap bitmap= Bitmap.createBitmap(view.getWidth(), view.getHeight(), HDConstantSet.BITMAP_QUALITY);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
另外可能要这样的问题:就是在滑动的view中这样操作的话会产生问题,具体的可以参照这篇博客:
View的getDrawingCache为空,解决办法