一、概述
需求:在分享的时候,可能会遇到需要 截取整个屏幕 或 截取屏幕一部分 的需求;
截图方案主要有以下两种:
- 开启
View.DrawingCache()
; - 调用
View.draw()
;
二、View的缓存
2.1 使用条件
-
使用DrawingCache,缓存的View需要显示在界面上。如果View没有添加到界面上或者没有显示(绘制)过,则
View.buildDrawingCache()
会失败。 -
缓存的View的大小不能超过 屏幕宽 * 屏幕高 * 4 的大小,否则会抛出异常;
// View.class private void buildDrawingCacheImpl(boolean autoScale) { mCachingFailed = false; int width = mRight - mLeft; int height = mBottom - mTop; // ...代码省略... 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); // 缓存的大小 = 屏幕宽 * 屏幕高 * 4 final long drawingCacheSize = ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize(); // projectedBitmapSize > drawingCacheSize 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; } // ...代码省略... }
2.2 使用场景
这种方式比较适合对应用界面或者某一部分的截图。
2.3 步骤
view.setDrawingCacheEnabled(true);
//启用DrawingCache并创建位图
view.buildDrawingCache();
Bitmap cacheBitmap = view.getDrawingCache();
//创建一个DrawingCache的拷贝,因为DrawingCache得到的位图在禁用后会被回收
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
//禁用DrawingCahce否则会影响性能
view.setDrawingCacheEnabled(false);
2.4 缺点
如果所需的截图没有显示在界面上(或者不可见),则即使开启View的缓存仍然不能获取所需的截图;
三、View.draw()
3.1 使用场景
分享的图没有显示在可见视图上 (分享的视图与可见视图不一致);
使用 Java代码 或者 inflate 创建;但是需要先指定View的大小,即调用下面的方法。
public void layoutView(View view, int width, int height) {
// validate view.width and view.height
view.layout(0, 0, width, height);
int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
// validate view.measurewidth and view.measureheight
view.measure(measuredWidth, measuredHeight);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
}
调用完上面的方法后,View和其内部的子View就有了实际大小,即完成了布局(相当于添加到了界面上)。
接着就可以创建位图并在上面绘制了:
// 创建截图
public void createBitmap(View view) {
int viewWidth = view.getMeasuredWidth();
int viewHeight = view.getMeasuredHeight();
if (viewWidth > 0 && viewHeight > 0) {
// 这里的bitmap就是所需的截图
Bitmap bitmap = Bitmap.createBitmap(viewWidth, viewHeight, Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap );
view.draw(canvas);
}
}