Take a screenshot of RecyclerView in FULL length

I want to get a full page screenshot. The view contains a RecyclerView with many elements.

I can take a screenshot of the current view using this function:

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; } 

But it contains only those elements that I can view normally (as expected).

Is there a way to make RecyclerView magically show its entirety (display all elements at once) when I take a screenshot?

If not, how can I approach this problem?

+8
source share
4 answers

Here is my solution for LinearLayoutManager when all elements are the same size and there is only one type of element . This decision is based on this answer .

Note This may result in a low memory error.

 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; } 

Note 2: It was originally written in Kotlin. Here is the original code used by me.

+13
source

Inspired by Joab's response. This code works for recyclerview item types and possibly regardless of size.

It has been tested using recyclerview with a linearlayout manager and three element types. However, to check this with other layout managers.

 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; } 
+15
source

Take a screenshot with a full overview of Recycler, regardless of its elements and types:

This piece of code works like a charm.

Here is an easy way to make it short and precise:

 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
source

I wrote a method to get a screenshot of several different views:

 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 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 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; } 
0
source

All Articles