我希望得到一个完整的页面"活动的屏幕截图。该视图包含一个包含许多项目的RecyclerView。
我可以使用此功能截取当前视图的屏幕截图:
public Bitmap getScreenBitmap() {
View v= findViewById(R.id.container).getRootView();
v.setDrawingCacheEnabled(true);
v.buildDrawingCache(true);
Bitmap b = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false); // clear drawing cache
return b;
}
但它只包含我可以正常查看的项目(如预期的那样)。
当我拍摄截图时,是否有某种方法可以让RecyclerView全神奇地显示(一次显示所有项目)?
如果没有,我应该如何解决这个问题?
答案 0 :(得分:13)
受到Yoav的回答的启发。此代码适用于recyclerview项目类型,可能与其大小无关。
使用具有linearlayout管理器和三种项目类型的recyclerview进行了测试。然而,要与其他布局经理一起检查。
public Bitmap getScreenshotFromRecyclerView(RecyclerView view) {
RecyclerView.Adapter adapter = view.getAdapter();
Bitmap bigBitmap = null;
if (adapter != null) {
int size = adapter.getItemCount();
int height = 0;
Paint paint = new Paint();
int iHeight = 0;
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// Use 1/8th of the available memory for this memory cache.
final int cacheSize = maxMemory / 8;
LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
for (int i = 0; i < size; i++) {
RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
adapter.onBindViewHolder(holder, i);
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
Bitmap drawingCache = holder.itemView.getDrawingCache();
if (drawingCache != null) {
bitmaCache.put(String.valueOf(i), drawingCache);
}
// holder.itemView.setDrawingCacheEnabled(false);
// holder.itemView.destroyDrawingCache();
height += holder.itemView.getMeasuredHeight();
}
bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
bigCanvas.drawColor(Color.WHITE);
for (int i = 0; i < size; i++) {
Bitmap bitmap = bitmaCache.get(String.valueOf(i));
bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
iHeight += bitmap.getHeight();
bitmap.recycle();
}
}
return bigBitmap;
}
答案 1 :(得分:12)
当所有项目的大小相同并且只有一种类型的项目时,以下是我LinearLayoutManager
的解决方案。此解决方案基于This answer。
注意:可能会导致内存不足错误。
public static Bitmap getRecyclerViewScreenshot(RecyclerView view) {
int size = view.getAdapter().getItemCount();
RecyclerView.ViewHolder holder = view.getAdapter().createViewHolder(view, 0);
view.getAdapter().onBindViewHolder(holder, 0);
holder.itemView.measure(View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(), holder.itemView.getMeasuredHeight());
Bitmap bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), holder.itemView.getMeasuredHeight() * size,
Bitmap.Config.ARGB_8888);
Canvas bigCanvas = new Canvas(bigBitmap);
bigCanvas.drawColor(Color.WHITE);
Paint paint = new Paint();
int iHeight = 0;
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
bigCanvas.drawBitmap(holder.itemView.getDrawingCache(), 0f, iHeight, paint);
holder.itemView.setDrawingCacheEnabled(false);
holder.itemView.destroyDrawingCache();
iHeight += holder.itemView.getMeasuredHeight();
for (int i = 1; i < size; i++) {
view.getAdapter().onBindViewHolder(holder, i);
holder.itemView.setDrawingCacheEnabled(true);
holder.itemView.buildDrawingCache();
bigCanvas.drawBitmap(holder.itemView.getDrawingCache(), 0f, iHeight, paint);
iHeight += holder.itemView.getMeasuredHeight();
holder.itemView.setDrawingCacheEnabled(false);
holder.itemView.destroyDrawingCache();
}
return bigBitmap;
}
注2:它最初是用Kotlin编写的。 Here是我使用的原始代码。
答案 2 :(得分:2)
获取完整的Recyclerview的屏幕快照,无论其项目和项目类型如何:
这段代码就像一个魅力。
这是一种简短而精确的干净方法:
recyclerView.measure(
View.MeasureSpec.makeMeasureSpec(recyclerView.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
Bitmap bm = Bitmap.createBitmap(recyclerView.getWidth(), recyclerView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
recyclerView.draw(new Canvas(bm));
saveImage(bm);
ImageView im
= new ImageView(getActivity());
im.setImageBitmap(bm);
new AlertDialog.Builder(getActivity()).setView(im).show();
答案 3 :(得分:1)
我找到的最佳解决方案是
创建一个新的NestedScrollView
将其添加到recyclerview的父级
从其父级删除recyclerview“将其添加到新的父级很重要”
将recyclerview添加到nestedscrollview
获取nestedscrollview的屏幕截图
将recyclerview添加到其主要父项。
nestedScreenShot = new NestedScrollView(getContext());
constraintLayout.removeView(recyclerView);
ConstraintLayout.LayoutParams params =new
Constraints.LayoutParams(viewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
nestedScreenShot.setLayoutParams(params);
Drawable scrollBackground = scrollView.getBackground();
if (scrollBackground != null) {
tempNestedScreenShot.setBackground(scrollBackground);
}
tempNestedScreenShot.setPadding(scrollView.getLeft(),
scrollView.getTop(), scrollView.getRight(), scrollView.getBottom());
constraintLayout.addView(nestedScreenShot);
nestedScreenShot.addView(recyclerView, params);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
nestedScreenShot.removeView(recyclerView);
constraintLayout.removeView(nestedScreenShot);
nestedScreenShot = null;
constraintLayout.addView(recyclerView, params);
}
}, 8000);
takescreenshotOfNested(nestedScreenShot);
此方法将返回nestedscrollview的屏幕截图
private Bitmap takescreenshotOfNested(View u) {
NestedScrollView viewNested = null;
ScrollView viewScroll = null;
if (u instanceof NestedScrollView) {
viewNested = (NestedScrollView) u;
} else if (u instanceof ScrollView) {
viewScroll = (ScrollView) u;
}
Bitmap bitmap;
if (viewNested != null) {
viewNested.setDrawingCacheEnabled(false);
viewNested.invalidate();
viewNested.getChildAt(0).setDrawingCacheEnabled(false);
viewNested.getChildAt(0).invalidate();
bitmap = Bitmap.createBitmap(viewNested.getChildAt(0).getWidth(),
viewNested.getChildAt(0).getHeight() + 8, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(activity.getResources().getColor(R.color.layout_background));
viewNested.draw(canvas);
} else {
try {
viewScroll.setDrawingCacheEnabled(false);
viewScroll.invalidate();
} catch (Exception ignored) {
}
viewScroll.getChildAt(0).setDrawingCacheEnabled(false);
viewScroll.getChildAt(0).invalidate();
bitmap = Bitmap.createBitmap(viewScroll.getChildAt(0).getWidth(),
viewScroll.getChildAt(0).getHeight() + 8, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(activity.getResources().getColor(R.color.layout_background));
viewScroll.draw(canvas);
}
return bitmap;
}
别忘了在使用位图后回收它
答案 4 :(得分:0)
我编写了一种方法来获取一些不同视图的屏幕截图:
private static Bitmap getBitmapFromView(View view) {
if (view.getVisibility() != View.VISIBLE) {
view = getNextView(view);
Log.d(TAG, "New view id: " + view.getId());
}
//Define a bitmap with the same size as the view
Bitmap returnedBitmap;
if (view instanceof ScrollView) {
returnedBitmap = Bitmap.createBitmap(((ViewGroup) view).getChildAt(0).getWidth(), ((ViewGroup) view).getChildAt(0).getHeight(), Bitmap.Config.ARGB_8888);
} else if (view instanceof RecyclerView) {
view.measure(
View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
} else {
returnedBitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
}
//Bind a canvas to it
Canvas canvas = new Canvas(returnedBitmap);
//Get the view's background
Drawable bgDrawable = view.getBackground();
if (bgDrawable != null) {
//has background drawable, then draw it on the canvas
bgDrawable.draw(canvas);
} else {
//does not have background drawable, then draw white background on the canvas
canvas.drawColor(Color.WHITE);
}
// draw the view on the canvas
view.draw(canvas);
//return the bitmap
return returnedBitmap;
}
/**
* If the base view is not visible, then it has no width or height.
* This causes a problem when we are creating a PDF based on its size.
* This method gets the next visible View.
*
* @param view The invisible view
* @return The next visible view after the given View, or the original view if there's no more
* visible views.
*/
private static View getNextView(View view) {
if (view.getParent() != null && (view.getParent() instanceof ViewGroup)) {
ViewGroup group = (ViewGroup) view.getParent();
View child;
boolean getNext = false;
//Iterate through all views from parent
for (int i = 0; i < group.getChildCount(); i++) {
child = group.getChildAt(i);
if (getNext) {
//Make sure the view is visible, else iterate again until we find a visible view
if (child.getVisibility() == View.VISIBLE) {
Log.d(TAG, String.format(Locale.ENGLISH, "CHILD: %s : %s", child.getClass().getSimpleName(), child.getId()));
view = child;
}
}
//Iterate until we find out current view,
// then we want to get the NEXT view
if (child.getId() == view.getId()) {
getNext = true;
}
}
}
return view;
}