Android 截图工具类
2019-10-31 本文已影响0人
afkT
DevUtils Github
CapturePictureUtils 截图工具类
支持 View、Activity、FrameLayout、RelativeLayout、LinearLayout、ListView、GridView、ScrollView、HorizontalScrollView、NestedScrollView、WebView、RecyclerView(GridLayoutManager、LinearLayoutManager、StaggeredGridLayoutManager)
- 截图工具类 -> CapturePictureUtils.java
方法 | 注释 |
---|---|
setBitmapConfig | 设置 Bitmap Config |
setBackgroundColor | 设置 Canvas 背景色 |
setPaint | 设置画笔 |
snapshotWithStatusBar | 获取当前屏幕截图, 包含状态栏 ( 顶部灰色 TitleBar 高度, 没有设置 android:theme 的 NoTitleBar 时会显示 ) |
snapshotWithoutStatusBar | 获取当前屏幕截图, 不包含状态栏 ( 如果 android:theme 全屏, 则截图无状态栏 ) |
enableSlowWholeDocumentDraw | 关闭 WebView 优化 |
snapshotByWebView | 截图 WebView |
snapshotByView | 通过 View 绘制为 Bitmap |
snapshotByViewCache | 通过 View Cache 绘制为 Bitmap |
snapshotByLinearLayout | 通过 LinearLayout 绘制为 Bitmap |
snapshotByFrameLayout | 通过 FrameLayout 绘制为 Bitmap |
snapshotByRelativeLayout | 通过 RelativeLayout 绘制为 Bitmap |
snapshotByScrollView | 通过 ScrollView 绘制为 Bitmap |
snapshotByHorizontalScrollView | 通过 HorizontalScrollView 绘制为 Bitmap |
snapshotByNestedScrollView | 通过 NestedScrollView 绘制为 Bitmap |
snapshotByListView | 通过 ListView 绘制为 Bitmap |
snapshotByGridView | 通过 GridView 绘制为 Bitmap |
snapshotByRecyclerView | 通过 RecyclerView 绘制为 Bitmap |
package dev.utils.app;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.v4.widget.NestedScrollView;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.webkit.WebView;
import android.widget.FrameLayout;
import android.widget.GridView;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.ScrollView;
import dev.DevUtils;
import dev.utils.LogPrintUtils;
/**
* detail: 截图工具类
* @author Ttt
* <pre>
* 截图
* @see <a href="https://www.cnblogs.com/angel88/p/7933437.html"/>
* WebView 截长图解决方案
* @see <a href="https://www.jianshu.com/p/0faa70e88441"/>
* X5 WebView 使用 snapshotWholePage 方法清晰截图
* @see <a href="https://www.v2ex.com/t/583020"/>
* </pre>
*/
public final class CapturePictureUtils {
private CapturePictureUtils() {
}
// 日志 TAG
private static final String TAG = CapturePictureUtils.class.getSimpleName();
// Bitmap Config
private static Bitmap.Config BITMAP_CONFIG = Bitmap.Config.RGB_565;
// Canvas 背景色
private static int BACKGROUND_COLOR = Color.TRANSPARENT;
// 画笔
private static Paint PAINT = new Paint();
// ============
// = 配置相关 =
// ============
/**
* 设置 Bitmap Config
* @param config {@link Bitmap.Config}
*/
public static void setBitmapConfig(final Bitmap.Config config) {
if (config == null) return;
BITMAP_CONFIG = config;
}
/**
* 设置 Canvas 背景色
* @param backgroundColor 背景色
*/
public static void setBackgroundColor(@ColorInt final int backgroundColor) {
BACKGROUND_COLOR = backgroundColor;
}
/**
* 设置画笔
* @param paint {@link Paint}
*/
public static void setPaint(final Paint paint) {
if (paint == null) return;
PAINT = paint;
}
// ========
// = 截图 =
// ========
// ============
// = Activity =
// ============
/**
* 获取当前屏幕截图, 包含状态栏 ( 顶部灰色 TitleBar 高度, 没有设置 android:theme 的 NoTitleBar 时会显示 )
* @param activity {@link Activity}
* @return 当前屏幕截图, 包含状态栏
*/
public static Bitmap snapshotWithStatusBar(final Activity activity) {
try {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
// 重新创建绘图缓存, 此时的背景色是黑色
view.buildDrawingCache();
// 获取绘图缓存, 注意这里得到的只是一个图像的引用
Bitmap cacheBitmap = view.getDrawingCache();
if (cacheBitmap == null) return null;
// 获取屏幕宽度
int[] widthHeight = getScreenWidthHeight();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
// 创建新的图片
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap, 0, 0, widthHeight[0], widthHeight[1]);
// 释放绘图资源所使用的缓存
view.destroyDrawingCache();
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotWithStatusBar");
}
return null;
}
/**
* 获取当前屏幕截图, 不包含状态栏 ( 如果 android:theme 全屏, 则截图无状态栏 )
* @param activity {@link Activity}
* @return 当前屏幕截图, 不包含状态栏
*/
public static Bitmap snapshotWithoutStatusBar(final Activity activity) {
try {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
// 重新创建绘图缓存, 此时的背景色是黑色
view.buildDrawingCache();
// 获取绘图缓存, 注意这里得到的只是一个图像的引用
Bitmap cacheBitmap = view.getDrawingCache();
if (cacheBitmap == null) return null;
// 获取屏幕宽度
int[] widthHeight = getScreenWidthHeight();
// 获取状态栏高度
int statusBarHeight = getStatusBarHeight(activity);
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
// 创建新的图片
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap, 0, statusBarHeight, widthHeight[0], widthHeight[1] - statusBarHeight);
// 释放绘图资源所使用的缓存
view.destroyDrawingCache();
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotWithoutStatusBar");
}
return null;
}
// ===========
// = WebView =
// ===========
/**
* 关闭 WebView 优化
* <pre>
* 推荐在 setContentView 前调用
* {@link CapturePictureUtils#snapshotByWebView}
* </pre>
*/
public static void enableSlowWholeDocumentDraw() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
android.webkit.WebView.enableSlowWholeDocumentDraw();
}
}
/**
* 截图 WebView
* @param webView {@link WebView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByWebView(final WebView webView) {
return snapshotByWebView(webView, Integer.MAX_VALUE, BITMAP_CONFIG, 0f);
}
/**
* 截图 WebView
* @param webView {@link WebView}
* @param maxHeight 最大高度
* @return {@link Bitmap}
*/
public static Bitmap snapshotByWebView(final WebView webView, final int maxHeight) {
return snapshotByWebView(webView, maxHeight, BITMAP_CONFIG, 0f);
}
/**
* 截图 WebView
* @param webView {@link WebView}
* @param scale 缩放比例
* @return {@link Bitmap}
*/
public static Bitmap snapshotByWebView(final WebView webView, final float scale) {
return snapshotByWebView(webView, Integer.MAX_VALUE, BITMAP_CONFIG, scale);
}
/**
* 截图 WebView
* @param webView {@link WebView}
* @param maxHeight 最大高度
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByWebView(final WebView webView, final int maxHeight, final Bitmap.Config config) {
return snapshotByWebView(webView, maxHeight, config, 0f);
}
/**
* 截图 WebView
* <pre>
* TODO 在 Android 5.0 及以上版本, Android 对 WebView 进行了优化, 为了减少内存使用和提高性能
* TODO 使用 WebView 加载网页时只绘制显示部分, 如果我们不做处理, 就会出现只截到屏幕内显示的 WebView 内容, 其它部分是空白的情况
* TODO 通过调用 WebView.enableSlowWholeDocumentDraw() 方法可以关闭这种优化, 但要注意的是, 该方法需要在 WebView 实例被创建前就要调用,
* TODO 否则没有效果, 所以我们在 WebView 实例被创建前加入代码
* {@link CapturePictureUtils#enableSlowWholeDocumentDraw}
* </pre>
* @param webView {@link WebView}
* @param maxHeight 最大高度
* @param config {@link Bitmap.Config}
* @param scale 缩放比例
* @return {@link Bitmap}
*/
public static Bitmap snapshotByWebView(final WebView webView, final int maxHeight,
final Bitmap.Config config, final float scale) {
if (webView != null && config != null) {
// Android 5.0 以上
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
try {
float newScale = scale;
if (newScale <= 0) {
// 该方法已抛弃, 可通过 setWebViewClient
// onScaleChanged(WebView view, float oldScale, float newScale)
// 存储并传入 newScale
newScale = webView.getScale();
}
int width = webView.getWidth();
int height = (int) (webView.getContentHeight() * newScale + 0.5);
// 重新设置高度
height = (height > maxHeight) ? maxHeight : height;
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
webView.draw(canvas);
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByWebView - SDK_INT >= 21(5.0)");
}
} else {
try {
Picture picture = webView.capturePicture();
int width = picture.getWidth();
int height = picture.getHeight();
if (width > 0 && height > 0) {
// 重新设置高度
height = (height > maxHeight) ? maxHeight : height;
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
picture.draw(canvas);
return bitmap;
}
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByWebView - SDK_INT < 21(5.0)");
}
}
}
return null;
}
// ========
// = View =
// ========
/**
* 通过 View 绘制为 Bitmap
* @param view {@link View}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByView(final View view) {
return snapshotByView(view, BITMAP_CONFIG);
}
/**
* 通过 View 绘制为 Bitmap
* @param view {@link View}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByView(final View view, final Bitmap.Config config) {
if (view == null || config == null) return null;
try {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
view.draw(canvas);
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByView");
}
return null;
}
/**
* 通过 View Cache 绘制为 Bitmap
* @param view {@link View}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByViewCache(final View view) {
if (view == null) return null;
try {
// 清除视图焦点
view.clearFocus();
// 将视图设为不可点击
view.setPressed(false);
// 获取视图是否可以保存画图缓存
boolean willNotCache = view.willNotCacheDrawing();
view.setWillNotCacheDrawing(false);
// 获取绘制缓存位图的背景颜色
int color = view.getDrawingCacheBackgroundColor();
// 设置绘图背景颜色
view.setDrawingCacheBackgroundColor(0);
if (color != 0) { // 获取的背景不是黑色的则释放以前的绘图缓存
view.destroyDrawingCache(); // 释放绘图资源所使用的缓存
}
// 重新创建绘图缓存, 此时的背景色是黑色
view.buildDrawingCache();
// 获取绘图缓存, 注意这里得到的只是一个图像的引用
Bitmap cacheBitmap = view.getDrawingCache();
if (cacheBitmap == null) return null;
Bitmap bitmap = Bitmap.createBitmap(cacheBitmap);
// 释放位图内存
view.destroyDrawingCache();
// 回滚以前的缓存设置、缓存颜色设置
view.setWillNotCacheDrawing(willNotCache);
view.setDrawingCacheBackgroundColor(color);
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByViewCache");
}
return null;
}
// ================
// = LinearLayout =
// ================
/**
* 通过 LinearLayout 绘制为 Bitmap
* @param linearLayout {@link LinearLayout}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByLinearLayout(final LinearLayout linearLayout) {
return snapshotByLinearLayout(linearLayout, BITMAP_CONFIG);
}
/**
* 通过 LinearLayout 绘制为 Bitmap
* <pre>
* LinearLayout 容器中不能有诸如 ListView、GridView、WebView 这样的高度可变的控件
* </pre>
* @param linearLayout {@link LinearLayout}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByLinearLayout(final LinearLayout linearLayout, final Bitmap.Config config) {
return snapshotByView(linearLayout, config);
}
// ===============
// = FrameLayout =
// ===============
/**
* 通过 FrameLayout 绘制为 Bitmap
* @param frameLayout {@link FrameLayout}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByFrameLayout(final FrameLayout frameLayout) {
return snapshotByFrameLayout(frameLayout, BITMAP_CONFIG);
}
/**
* 通过 FrameLayout 绘制为 Bitmap
* <pre>
* FrameLayout 容器中不能有诸如 ListView、GridView、WebView 这样的高度可变的控件
* </pre>
* @param frameLayout {@link FrameLayout}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByFrameLayout(final FrameLayout frameLayout, final Bitmap.Config config) {
return snapshotByView(frameLayout, config);
}
// ==================
// = RelativeLayout =
// ==================
/**
* 通过 RelativeLayout 绘制为 Bitmap
* @param relativeLayout {@link RelativeLayout}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRelativeLayout(final RelativeLayout relativeLayout) {
return snapshotByRelativeLayout(relativeLayout, BITMAP_CONFIG);
}
/**
* 通过 RelativeLayout 绘制为 Bitmap
* <pre>
* RelativeLayout 容器中不能有诸如 ListView、GridView、WebView 这样的高度可变的控件
* </pre>
* @param relativeLayout {@link RelativeLayout}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRelativeLayout(final RelativeLayout relativeLayout, final Bitmap.Config config) {
return snapshotByView(relativeLayout, config);
}
// ==============
// = ScrollView =
// ==============
/**
* 通过 ScrollView 绘制为 Bitmap
* @param scrollView {@link ScrollView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByScrollView(final ScrollView scrollView) {
return snapshotByScrollView(scrollView, BITMAP_CONFIG);
}
/**
* 通过 ScrollView 绘制为 Bitmap
* <pre>
* ScrollView 容器中不能有诸如 ListView、GridView、WebView 这样的高度可变的控件
* </pre>
* @param scrollView {@link ScrollView}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByScrollView(final ScrollView scrollView, final Bitmap.Config config) {
if (scrollView == null || config == null) return null;
try {
View view = scrollView.getChildAt(0);
int width = view.getWidth();
int height = view.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
scrollView.layout(0, 0, scrollView.getMeasuredWidth(),
scrollView.getMeasuredHeight());
scrollView.draw(canvas);
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByScrollView");
}
return null;
}
// ========================
// = HorizontalScrollView =
// ========================
/**
* 通过 HorizontalScrollView 绘制为 Bitmap
* @param scrollView {@link HorizontalScrollView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByHorizontalScrollView(final HorizontalScrollView scrollView) {
return snapshotByHorizontalScrollView(scrollView, BITMAP_CONFIG);
}
/**
* 通过 HorizontalScrollView 绘制为 Bitmap
* @param scrollView {@link HorizontalScrollView}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByHorizontalScrollView(final HorizontalScrollView scrollView, final Bitmap.Config config) {
if (scrollView == null || config == null) return null;
try {
View view = scrollView.getChildAt(0);
int width = view.getWidth();
int height = view.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
scrollView.layout(0, 0, scrollView.getMeasuredWidth(),
scrollView.getMeasuredHeight());
scrollView.draw(canvas);
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByHorizontalScrollView");
}
return null;
}
// ====================
// = NestedScrollView =
// ====================
/**
* 通过 NestedScrollView 绘制为 Bitmap
* @param scrollView {@link NestedScrollView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByNestedScrollView(final NestedScrollView scrollView) {
return snapshotByNestedScrollView(scrollView, BITMAP_CONFIG);
}
/**
* 通过 NestedScrollView 绘制为 Bitmap
* @param scrollView {@link NestedScrollView}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByNestedScrollView(final NestedScrollView scrollView, final Bitmap.Config config) {
if (scrollView == null || config == null) return null;
try {
View view = scrollView.getChildAt(0);
int width = view.getWidth();
int height = view.getHeight();
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
scrollView.layout(0, 0, scrollView.getMeasuredWidth(),
scrollView.getMeasuredHeight());
scrollView.draw(canvas);
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByNestedScrollView");
}
return null;
}
// ============
// = ListView =
// ============
/**
* 通过 ListView 绘制为 Bitmap
* @param listView {@link ListView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByListView(final ListView listView) {
return snapshotByListView(listView, BITMAP_CONFIG);
}
/**
* 通过 ListView 绘制为 Bitmap
* @param listView {@link ListView}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByListView(final ListView listView, final Bitmap.Config config) {
if (listView == null || config == null) return null;
try {
// Adapter
ListAdapter listAdapter = listView.getAdapter();
// Item 总条数
int itemCount = listAdapter.getCount();
// 没数据则直接跳过
if (itemCount == 0) return null;
// 高度
int height = 0;
// 获取子项间分隔符占用的高度
int dividerHeight = listView.getDividerHeight();
// View Bitmaps
Bitmap[] bitmaps = new Bitmap[itemCount];
// 循环绘制每个 Item 并保存 Bitmap
for (int i = 0; i < itemCount; i++) {
View childView = listAdapter.getView(i, null, listView);
measureView(childView, listView.getWidth());
bitmaps[i] = canvasBitmap(childView, config);
height += childView.getMeasuredHeight();
}
// 追加子项间分隔符占用的高度
height += (dividerHeight * (itemCount - 1));
int width = listView.getMeasuredWidth();
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加高度
int appendHeight = 0;
for (int i = 0, len = bitmaps.length; i < len; i++) {
Bitmap bmp = bitmaps[i];
canvas.drawBitmap(bmp, 0, appendHeight, PAINT);
appendHeight += (bmp.getHeight() + dividerHeight);
// 释放资源
bmp.recycle();
bmp = null;
}
return bitmap;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByListView");
}
return null;
}
// ============
// = GridView =
// ============
/**
* 通过 GridView 绘制为 Bitmap
* @param gridView {@link GridView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByGridView(final GridView gridView) {
return snapshotByGridView(gridView, BITMAP_CONFIG, false);
}
/**
* 通过 GridView 绘制为 Bitmap
* @param gridView {@link GridView}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByGridView(final GridView gridView, final Bitmap.Config config) {
return snapshotByGridView(gridView, config, false);
}
/**
* 通过 GridView 绘制为 Bitmap
* @param gridView {@link GridView}
* @param config {@link Bitmap.Config}
* @param listViewEffect 是否保存 ListView 效果 ( 每个 Item 铺满 )
* @return {@link Bitmap}
*/
public static Bitmap snapshotByGridView(final GridView gridView, final Bitmap.Config config, final boolean listViewEffect) {
if (gridView == null || config == null) return null;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) return null;
try {
// Adapter
ListAdapter listAdapter = gridView.getAdapter();
// Item 总条数
int itemCount = listAdapter.getCount();
// 没数据则直接跳过
if (itemCount == 0) return null;
// 高度
int height = 0;
// 获取一共多少列
int numColumns = gridView.getNumColumns();
// 每列之间的间隔 |
int horizontalSpacing = gridView.getHorizontalSpacing();
// 每行之间的间隔 -
int verticalSpacing = gridView.getVerticalSpacing();
// View Bitmaps
Bitmap[] bitmaps = new Bitmap[itemCount];
// 效果处理 - ListView 效果 Item 铺满
if (listViewEffect) {
// 循环绘制每个 Item 并保存 Bitmap
for (int i = 0; i < itemCount; i++) {
View childView = listAdapter.getView(i, null, gridView);
measureView(childView, gridView.getWidth());
bitmaps[i] = canvasBitmap(childView, config);
height += childView.getMeasuredHeight();
}
// 追加子项间分隔符占用的高度
height += (verticalSpacing * (itemCount - 1));
int width = gridView.getMeasuredWidth();
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加高度
int appendHeight = 0;
for (int i = 0, len = bitmaps.length; i < len; i++) {
Bitmap bmp = bitmaps[i];
canvas.drawBitmap(bmp, 0, appendHeight, PAINT);
appendHeight += (bmp.getHeight() + verticalSpacing);
// 释放资源
bmp.recycle();
bmp = null;
}
return bitmap;
} else {
// 获取倍数 ( 行数 )
int lineNumber = getMultiple(itemCount, numColumns);
// 计算总共的宽度 - (GridView 宽度 - 列分割间距 ) / numColumns
int childWidth = (gridView.getWidth() - (numColumns - 1) * horizontalSpacing) / numColumns;
// 记录每行最大高度
int[] rowHeightArrays = new int[lineNumber];
// 临时高度 - 保存行中最高的列高度
int tempHeight;
// 循环每一行绘制每个 Item 并保存 Bitmap
for (int i = 0; i < lineNumber; i++) {
// 清空高度
tempHeight = 0;
// 循环列数
for (int j = 0; j < numColumns; j++) {
// 获取对应的索引
int position = i * numColumns + j;
// 小于总数才处理
if (position < itemCount) {
View childView = listAdapter.getView(position, null, gridView);
measureView(childView, childWidth);
bitmaps[position] = canvasBitmap(childView, config);
int itemHeight = childView.getMeasuredHeight();
// 保留最大高度
tempHeight = Math.max(itemHeight, tempHeight);
}
// 记录高度并累加
if (j == numColumns - 1) {
height += tempHeight;
rowHeightArrays[i] = tempHeight;
}
}
}
// 追加子项间分隔符占用的高度
height += (verticalSpacing * (lineNumber - 1));
int width = gridView.getMeasuredWidth();
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加高度
int appendHeight = 0;
// 循环每一行绘制每个 Item Bitmap
for (int i = 0; i < lineNumber; i++) {
// 获取每一行最长列的高度
int itemHeight = rowHeightArrays[i];
// 循环列数
for (int j = 0; j < numColumns; j++) {
// 获取对应的索引
int position = i * numColumns + j;
// 小于总数才处理
if (position < itemCount) {
Bitmap bmp = bitmaps[position];
// 计算边距
int left = j * (horizontalSpacing + childWidth);
Matrix matrix = new Matrix();
matrix.postTranslate(left, appendHeight);
// 绘制到 Bitmap
canvas.drawBitmap(bmp, matrix, PAINT);
// 释放资源
bmp.recycle();
bmp = null;
}
// 记录高度并累加
if (j == numColumns - 1) {
appendHeight += itemHeight + verticalSpacing;
}
}
}
return bitmap;
}
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByGridView");
}
return null;
}
// ================
// = RecyclerView =
// ================
/**
* 通过 RecyclerView 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRecyclerView(final RecyclerView recyclerView) {
return snapshotByRecyclerView(recyclerView, BITMAP_CONFIG, 0, 0);
}
/**
* 通过 RecyclerView 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRecyclerView(final RecyclerView recyclerView,
final Bitmap.Config config) {
return snapshotByRecyclerView(recyclerView, config, 0, 0);
}
/**
* 通过 RecyclerView 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @param spacing 每列之间的间隔 |
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRecyclerView(final RecyclerView recyclerView, final int spacing) {
return snapshotByRecyclerView(recyclerView, BITMAP_CONFIG, spacing, spacing);
}
/**
* 通过 RecyclerView 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @param config {@link Bitmap.Config}
* @param spacing 每列之间的间隔 |
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRecyclerView(final RecyclerView recyclerView,
final Bitmap.Config config, final int spacing) {
return snapshotByRecyclerView(recyclerView, config, spacing, spacing);
}
/**
* 通过 RecyclerView 绘制为 Bitmap
* <pre>
* 不支持含 ItemDecoration 截图
* 如果数据太多推荐 copy 代码, 修改为保存每个 Item Bitmap 到本地, 并在绘制时获取绘制
* </pre>
* @param recyclerView {@link RecyclerView}
* @param config {@link Bitmap.Config}
* @param verticalSpacing 每行之间的间隔 -
* @param horizontalSpacing 每列之间的间隔 |
* @return {@link Bitmap}
*/
public static Bitmap snapshotByRecyclerView(final RecyclerView recyclerView, final Bitmap.Config config,
final int verticalSpacing, final int horizontalSpacing) {
if (recyclerView == null || config == null) return null;
try {
// 获取适配器
RecyclerView.Adapter adapter = recyclerView.getAdapter();
// 获取布局管理器
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager != null && adapter != null) {
// 判断布局类型
if (layoutManager instanceof GridLayoutManager) {
return snapshotByRecyclerView_GridLayoutManager(recyclerView,
config, verticalSpacing, horizontalSpacing);
} else if (layoutManager instanceof LinearLayoutManager) {
return snapshotByRecyclerView_LinearLayoutManager(recyclerView,
config, verticalSpacing, horizontalSpacing);
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
return snapshotByRecyclerView_StaggeredGridLayoutManager(recyclerView,
config, verticalSpacing, horizontalSpacing);
}
throw new Exception(String.format("Not Supported %s LayoutManager", layoutManager.getClass().getSimpleName()));
} else {
throw new Exception("Adapter or LayoutManager is Null");
}
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByRecyclerView");
}
return null;
}
// =================
// = LayoutManager =
// =================
/**
* 通过 RecyclerView GridLayoutManager 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @param config {@link Bitmap.Config}
* @param verticalSpacing 每行之间的间隔 -
* @param horizontalSpacing 每列之间的间隔 |
* @return {@link Bitmap}
*/
private static Bitmap snapshotByRecyclerView_GridLayoutManager(final RecyclerView recyclerView,
final Bitmap.Config config,
final int verticalSpacing,
final int horizontalSpacing) {
// 计算思路
// = 竖屏 =
// 每个 Item 宽度最大值固定为 (RecyclerView 宽度 - ( 列数 - 1) * 每列边距 ) / 列数
// 循环保存每行最大高度, 并累加每行之间的间隔, 用于 Bitmap 高度, 宽度用 RecyclerView 宽度
// = 横屏 =
// 循环保存每一行宽度以及每一行 ( 横着一行 ) 最大高度, 并且累加每行、每列之间的间隔
// 用于 Bitmap 高度, 宽度用 ( 每一行宽度累加值 ) 最大值
try {
// 获取适配器
RecyclerView.Adapter adapter = recyclerView.getAdapter();
// Item 总条数
int itemCount = adapter.getItemCount();
// 没数据则直接跳过
if (itemCount == 0) return null;
// 宽高
int width = 0, height = 0;
// View Bitmaps
Bitmap[] bitmaps = new Bitmap[itemCount];
// 获取布局管理器 - 判断横竖布局
GridLayoutManager gridLayoutManager = (GridLayoutManager) recyclerView.getLayoutManager();
boolean vertical = (gridLayoutManager.getOrientation() == 1);
// 获取一共多少列
int spanCount = gridLayoutManager.getSpanCount();
// 获取倍数 ( 行数 )
int lineNumber = getMultiple(itemCount, spanCount);
if (vertical) {
// ============
// = 竖向滑动 =
// ============
// 计算总共的宽度 - (GridView 宽度 - 列分割间距 ) / spanCount
int childWidth = (recyclerView.getWidth() - (spanCount - 1) * horizontalSpacing) / spanCount;
// 记录每行最大高度
int[] rowHeightArrays = new int[lineNumber];
// 临时高度 - 保存行中最高的列高度
int tempHeight;
for (int i = 0; i < lineNumber; i++) {
// 清空高度
tempHeight = 0;
// 循环列数
for (int j = 0; j < spanCount; j++) {
// 获取对应的索引
int position = i * spanCount + j;
// 小于总数才处理
if (position < itemCount) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(position));
adapter.onBindViewHolder(holder, position);
View childView = holder.itemView;
measureView(childView, childWidth);
bitmaps[position] = canvasBitmap(childView, config);
int itemHeight = childView.getMeasuredHeight();
// 保留最大高度
tempHeight = Math.max(itemHeight, tempHeight);
}
// 记录高度并累加
if (j == spanCount - 1) {
height += tempHeight;
rowHeightArrays[i] = tempHeight;
}
}
}
// 追加子项间分隔符占用的高度
height += (verticalSpacing * (lineNumber - 1));
width = recyclerView.getMeasuredWidth();
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加高度
int appendHeight = 0;
for (int i = 0; i < lineNumber; i++) {
// 获取每行中最高的列高度
int rowHeight = rowHeightArrays[i];
// 循环列数
for (int j = 0; j < spanCount; j++) {
// 获取对应的索引
int position = i * spanCount + j;
// 小于总数才处理
if (position < itemCount) {
Bitmap bmp = bitmaps[position];
// 计算边距
int left = j * (horizontalSpacing + childWidth);
Matrix matrix = new Matrix();
matrix.postTranslate(left, appendHeight);
// 绘制到 Bitmap
canvas.drawBitmap(bmp, matrix, PAINT);
// 释放资源
bmp.recycle();
bmp = null;
}
// 记录高度并累加
if (j == spanCount - 1) {
appendHeight += (rowHeight + verticalSpacing);
}
}
}
return bitmap;
} else {
// ============
// = 横向滑动 =
// ============
// 获取行数
lineNumber = Math.min(spanCount, itemCount);
// 记录每一行宽度
int[] rowWidthArrays = new int[lineNumber];
// 记录每一行高度
int[] rowHeightArrays = new int[lineNumber];
// 获取一共多少列
int numColumns = getMultiple(itemCount, lineNumber);
// 临时高度 - 保存行中最高的列高度
int tempHeight;
for (int i = 0; i < lineNumber; i++) {
// 清空高度
tempHeight = 0;
// 循环列数
for (int j = 0; j < numColumns; j++) {
// 获取对应的索引
int position = j * lineNumber + i;
// 小于总数才处理
if (position < itemCount) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(position));
adapter.onBindViewHolder(holder, position);
View childView = holder.itemView;
measureView(childView, 0);
bitmaps[position] = canvasBitmap(childView, config);
rowWidthArrays[i] += childView.getMeasuredWidth();
int itemHeight = childView.getMeasuredHeight();
// 保留最大高度
tempHeight = Math.max(itemHeight, tempHeight);
}
// 最后记录处理
if (j == numColumns - 1) {
height += tempHeight;
width = Math.max(width, rowWidthArrays[i]);
rowHeightArrays[i] = tempHeight;
}
}
}
// 追加子项间分隔符占用的高、宽
height += (verticalSpacing * (lineNumber - 1));
width += (horizontalSpacing * (numColumns - 1));
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加宽、高
int appendWidth = 0, appendHeight = 0;
for (int i = 0; i < lineNumber; i++) {
// 获取每行中最高的列高度
int rowHeight = rowHeightArrays[i];
// 循环列数
for (int j = 0; j < numColumns; j++) {
// 获取对应的索引
int position = j * lineNumber + i;
// 小于总数才处理
if (position < itemCount) {
Bitmap bmp = bitmaps[position];
// 计算边距
int left = appendWidth + (j * horizontalSpacing);
Matrix matrix = new Matrix();
matrix.postTranslate(left, appendHeight);
// 绘制到 Bitmap
canvas.drawBitmap(bmp, matrix, PAINT);
// 累加 Bitmap 宽度
appendWidth += bmp.getWidth();
// 释放资源
bmp.recycle();
bmp = null;
}
// 记录高度并累加
if (j == numColumns - 1) {
appendWidth = 0;
appendHeight += (rowHeight + verticalSpacing);
}
}
}
return bitmap;
}
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByRecyclerView_GridLayoutManager");
}
return null;
}
/**
* 通过 RecyclerView LinearLayoutManager 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @param config {@link Bitmap.Config}
* @param verticalSpacing 每行之间的间隔 -
* @param horizontalSpacing 每列之间的间隔 |
* @return {@link Bitmap}
*/
private static Bitmap snapshotByRecyclerView_LinearLayoutManager(final RecyclerView recyclerView,
final Bitmap.Config config,
final int verticalSpacing,
final int horizontalSpacing) {
// 计算思路
// = 竖屏 =
// 循环保存每一个 Item View 高度, 并累加每行之间的间隔,
// 用于 Bitmap 高度, 宽度用 RecyclerView 宽度
// = 横屏 =
// 循环保存每一个 Item View 宽度, 并累加每列之间的间隔, 且记录最高的列
// 用于 Bitmap 高度, 宽度用累加出来的值
try {
// 获取适配器
RecyclerView.Adapter adapter = recyclerView.getAdapter();
// Item 总条数
int itemCount = adapter.getItemCount();
// 没数据则直接跳过
if (itemCount == 0) return null;
// 宽高
int width = 0, height = 0;
// View Bitmaps
Bitmap[] bitmaps = new Bitmap[itemCount];
// 获取布局管理器 - 判断横竖布局
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
boolean vertical = (linearLayoutManager.getOrientation() == 1);
if (vertical) {
// ============
// = 竖向滑动 =
// ============
for (int i = 0; i < itemCount; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
View childView = holder.itemView;
measureView(childView, recyclerView.getWidth());
bitmaps[i] = canvasBitmap(childView, config);
height += childView.getMeasuredHeight();
}
// 追加子项间分隔符占用的高度
height += (verticalSpacing * (itemCount - 1));
width = recyclerView.getMeasuredWidth();
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加高度
int appendHeight = 0;
for (int i = 0; i < itemCount; i++) {
Bitmap bmp = bitmaps[i];
canvas.drawBitmap(bmp, 0, appendHeight, PAINT);
appendHeight += (bmp.getHeight() + verticalSpacing);
// 释放资源
bmp.recycle();
bmp = null;
}
return bitmap;
} else {
// ============
// = 横向滑动 =
// ============
// 临时高度 - 保存行中最高的列高度
int tempHeight = 0;
for (int i = 0; i < itemCount; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
View childView = holder.itemView;
measureView(childView, 0);
bitmaps[i] = canvasBitmap(childView, config);
width += childView.getMeasuredWidth();
int itemHeight = childView.getMeasuredHeight();
// 保留最大高度
tempHeight = Math.max(itemHeight, tempHeight);
}
// 追加子项间分隔符占用的宽度
width += (horizontalSpacing * (itemCount - 1));
height = tempHeight;
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 累加宽度
int appendWidth = 0;
for (int i = 0; i < itemCount; i++) {
Bitmap bmp = bitmaps[i];
canvas.drawBitmap(bmp, appendWidth, 0, PAINT);
appendWidth += (bmp.getWidth() + horizontalSpacing);
// 释放资源
bmp.recycle();
bmp = null;
}
return bitmap;
}
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByRecyclerView_LinearLayoutManager");
}
return null;
}
/**
* 通过 RecyclerView StaggeredGridLayoutManager 绘制为 Bitmap
* @param recyclerView {@link RecyclerView}
* @param config {@link Bitmap.Config}
* @param verticalSpacing 每行之间的间隔 -
* @param horizontalSpacing 每列之间的间隔 |
* @return {@link Bitmap}
*/
private static Bitmap snapshotByRecyclerView_StaggeredGridLayoutManager(final RecyclerView recyclerView,
final Bitmap.Config config,
final int verticalSpacing,
final int horizontalSpacing) {
// 计算思路
// = 竖屏 =
// 每个 Item 宽度最大值固定为 (RecyclerView 宽度 - ( 列数 - 1) * 每列边距 ) / 列数
// 循环保存每一个 Item View 高度, 并创建数组记录每一列待绘制高度, 实现瀑布流高度补差
// 并通过该数组 ( 每列待绘制高度数组 ) 获取最大值, 用做 Bitmap 高度, 绘制则还是按以上规则高度补差累加
// = 横屏 =
// 循环保存每一个 Item View 宽度、高度, 并创建数组记录每一列待绘制宽度, 实现瀑布流高度补差
// 并通过该数组 ( 每列待绘制宽度数组 ) 获取最大值, 用做 Bitmap 高度, 绘制则还是按以上规则宽度补差累加
try {
// 获取适配器
RecyclerView.Adapter adapter = recyclerView.getAdapter();
// Item 总条数
int itemCount = adapter.getItemCount();
// 没数据则直接跳过
if (itemCount == 0) return null;
// 宽高
int width = 0, height = 0;
// View Bitmaps
Bitmap[] bitmaps = new Bitmap[itemCount];
// 获取布局管理器 - 判断横竖布局
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) recyclerView.getLayoutManager();
boolean vertical = (staggeredGridLayoutManager.getOrientation() == 1);
// 获取一共多少列
int spanCount = staggeredGridLayoutManager.getSpanCount();
// 获取倍数 ( 行数 )
int lineNumber = getMultiple(itemCount, spanCount);
if (vertical) {
// ============
// = 竖向滑动 =
// ============
// 计算总共的宽度 - (GridView 宽度 - 列分割间距 ) / spanCount
int childWidth = (recyclerView.getWidth() - (spanCount - 1) * horizontalSpacing) / spanCount;
// 记录每个 Item 高度
int[] itemHeightArrays = new int[itemCount];
for (int i = 0; i < itemCount; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
View childView = holder.itemView;
measureView(childView, childWidth);
bitmaps[i] = canvasBitmap(childView, config);
itemHeightArrays[i] = childView.getMeasuredHeight();
}
// 记录每列 Item 个数
int[] columnsItemNumberArrays = new int[spanCount];
// 记录每列总高度
int[] columnsHeightArrays = new int[spanCount];
// 循环高度, 计算绘制位置
for (int i = 0; i < itemCount; i++) {
// 获取最小高度索引
int minIndex = getMinimumIndex(columnsHeightArrays);
// 累加高度
columnsHeightArrays[minIndex] += itemHeightArrays[i];
// 累加数量
columnsItemNumberArrays[minIndex] += 1;
}
// 计算高度 - 追加子项间分隔符占用的高度
if (lineNumber >= 2) {
// 循环追加子项间分隔符占用的高度
for (int i = 0; i < spanCount; i++) {
columnsHeightArrays[i] += (columnsItemNumberArrays[i] - 1) * verticalSpacing;
}
}
// 获取列最大高度索引
int columnsHeightMaxIndex = getMaximumIndex(columnsHeightArrays);
// 获取最大高度值
int maxColumnsHeight = columnsHeightArrays[columnsHeightMaxIndex];
// 使用最大值
height = maxColumnsHeight;
width = recyclerView.getMeasuredWidth();
// 清空绘制时累加计算
columnsHeightArrays = new int[spanCount];
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 循环绘制
for (int i = 0; i < itemCount; i++) {
// 获取最小高度索引
int minIndex = getMinimumIndex(columnsHeightArrays);
// 计算边距
int left = minIndex * (horizontalSpacing + childWidth);
Matrix matrix = new Matrix();
matrix.postTranslate(left, columnsHeightArrays[minIndex]);
// 绘制到 Bitmap
Bitmap bmp = bitmaps[i];
canvas.drawBitmap(bmp, matrix, PAINT);
// 累加高度
columnsHeightArrays[minIndex] += (itemHeightArrays[i] + verticalSpacing);
// 释放资源
bmp.recycle();
bmp = null;
}
return bitmap;
} else {
// ============
// = 横向滑动 =
// ============
// 获取行数
lineNumber = Math.min(spanCount, itemCount);
// 记录每个 Item 宽度
int[] itemWidthArrays = new int[itemCount];
// 记录每个 Item 高度
int[] itemHeightArrays = new int[itemCount];
for (int i = 0; i < itemCount; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(recyclerView, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
View childView = holder.itemView;
measureView(childView, 0);
bitmaps[i] = canvasBitmap(childView, config);
itemWidthArrays[i] = childView.getMeasuredWidth();
itemHeightArrays[i] = childView.getMeasuredHeight();
}
// 记录每行向上距离
int[] columnsTopArrays = new int[lineNumber];
// 记录每行 Item 个数
int[] columnsItemNumberArrays = new int[lineNumber];
// 记录每行总宽度
int[] columnsWidthArrays = new int[lineNumber];
// 记录每行最大高度
int[] columnsHeightArrays = new int[lineNumber];
// 循环宽度, 计算绘制位置
for (int i = 0; i < itemCount; i++) {
// 获取最小宽度索引
int minIndex = getMinimumIndex(columnsWidthArrays);
// 累加宽度
columnsWidthArrays[minIndex] += itemWidthArrays[i];
// 累加数量
columnsItemNumberArrays[minIndex] += 1;
// 保存每行最大高度
columnsHeightArrays[minIndex] = Math.max(itemHeightArrays[i], columnsHeightArrays[minIndex]);
}
// 循环追加子项间分隔符占用的宽度
for (int i = 0; i < lineNumber; i++) {
if (columnsItemNumberArrays[i] > 1) {
columnsWidthArrays[i] += (columnsItemNumberArrays[i] - 1) * horizontalSpacing;
}
if (i > 0) {
columnsTopArrays[i] = height + (i * verticalSpacing);
}
// 累加每行高度
height += columnsHeightArrays[i];
}
// 获取最大宽值
int maxColumnsWidth = columnsWidthArrays[getMaximumIndex(columnsWidthArrays)];
// 使用最大值
height += (lineNumber - 1) * verticalSpacing;
width = maxColumnsWidth;
// 清空绘制时累加计算
columnsWidthArrays = new int[lineNumber];
// 创建位图
Bitmap bitmap = Bitmap.createBitmap(width, height, config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
// 循环绘制
for (int i = 0; i < itemCount; i++) {
// 获取最小宽度索引
int minIndex = getMinimumIndex(columnsWidthArrays);
Matrix matrix = new Matrix();
matrix.postTranslate(columnsWidthArrays[minIndex], columnsTopArrays[minIndex]);
// 绘制到 Bitmap
Bitmap bmp = bitmaps[i];
canvas.drawBitmap(bmp, matrix, PAINT);
// 累加宽度
columnsWidthArrays[minIndex] += (itemWidthArrays[i] + horizontalSpacing);
// 释放资源
bmp.recycle();
bmp = null;
}
return bitmap;
}
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "snapshotByRecyclerView_StaggeredGridLayoutManager");
}
return null;
}
// ================
// = 内部私有方法 =
// ================
/**
* 绘制 Bitmap
* @param childView {@link View}
* @param config {@link Bitmap.Config}
* @return {@link Bitmap}
*/
private static Bitmap canvasBitmap(final View childView, final Bitmap.Config config) {
Bitmap bitmap = Bitmap.createBitmap(childView.getMeasuredWidth(), childView.getMeasuredHeight(), config);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(BACKGROUND_COLOR);
childView.draw(canvas);
return bitmap;
}
// ======================
// = 其他工具类实现代码 =
// ======================
// ===============
// = ScreenUtils =
// ===============
/**
* 获取屏幕宽高
* @return int[], 0 = 宽度, 1 = 高度
*/
private static int[] getScreenWidthHeight() {
try {
WindowManager windowManager = (WindowManager) DevUtils.getContext().getSystemService(Context.WINDOW_SERVICE);
if (windowManager == null) {
DisplayMetrics displayMetrics = DevUtils.getContext().getResources().getDisplayMetrics();
return new int[]{displayMetrics.widthPixels, displayMetrics.heightPixels};
}
Point point = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
windowManager.getDefaultDisplay().getRealSize(point);
} else {
windowManager.getDefaultDisplay().getSize(point);
}
return new int[]{point.x, point.y};
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "getScreenWidthHeight");
}
return new int[]{0, 0};
}
/**
* 获取应用区域 TitleBar 高度 ( 顶部灰色 TitleBar 高度, 没有设置 android:theme 的 NoTitleBar 时会显示 )
* @param activity {@link Activity}
* @return 应用区域 TitleBar 高度
*/
private static int getStatusBarHeight(final Activity activity) {
try {
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
return rect.top;
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "getStatusBarHeight");
}
return 0;
}
// ===============
// = NumberUtils =
// ===============
/**
* 获取倍数 ( 自动补 1)
* @param value 被除数
* @param divisor 除数
* @return 倍数
*/
private static int getMultiple(final int value, final int divisor) {
if (value <= 0 || divisor <= 0) return 0;
if (value <= divisor) return 1;
return (value % divisor == 0) ? (value / divisor) : (value / divisor) + 1;
}
// ==============
// = ArrayUtils =
// ==============
/**
* 获取数组中最小值索引
* @param data 数组
* @return 最小值索引
*/
private static int getMinimumIndex(final int[] data) {
if (data != null) {
int len = data.length;
if (len > 0) {
int index = 0;
int temp = data[index];
for (int i = 1; i < len; i++) {
int value = data[i];
if (value < temp) {
index = i;
temp = value;
}
}
return index;
}
}
return -1;
}
/**
* 获取数组中最大值索引
* @param data 数组
* @return 最大值索引
*/
private static int getMaximumIndex(final int[] data) {
if (data != null) {
int len = data.length;
if (len > 0) {
int index = 0;
int temp = data[index];
for (int i = 1; i < len; i++) {
int value = data[i];
if (value > temp) {
index = i;
temp = value;
}
}
return index;
}
}
return -1;
}
// =============
// = ViewUtils =
// =============
/**
* 测量 View
* @param view {@link View}
* @param specifiedWidth 指定宽度
*/
private static void measureView(final View view, final int specifiedWidth) {
measureView(view, specifiedWidth, 0);
}
/**
* 测量 View
* @param view {@link View}
* @param specifiedWidth 指定宽度
* @param specifiedHeight 指定高度
*/
private static void measureView(final View view, final int specifiedWidth, final int specifiedHeight) {
try {
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
// MeasureSpec
int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
// 如果大于 0
if (specifiedWidth > 0) {
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(specifiedWidth, View.MeasureSpec.EXACTLY);
}
// 如果大于 0
if (specifiedHeight > 0) {
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(specifiedHeight, View.MeasureSpec.EXACTLY);
}
// 判断是否存在自定义宽高
if (layoutParams != null) {
int width = layoutParams.width;
int height = layoutParams.height;
if (width > 0 && height > 0) {
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
} else if (width > 0) {
widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
} else if (height > 0) {
heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);
}
}
view.measure(widthMeasureSpec, heightMeasureSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
} catch (Exception e) {
LogPrintUtils.eTag(TAG, e, "measureView");
}
}
}