Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Take a screenshot of RecyclerView in FULL length

Tags:

java

android

I want to get a "full page" screenshot of the activity. The view contains a RecyclerView with many items.

I can take a screenshot of the current view with 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 the items I can view normally (as expected).

Is there some way to make the RecyclerView magically show in full length (display all items at once) when I take the screenshot?

If not, how should I approach this problem?

like image 632
davis Avatar asked May 06 '15 18:05

davis


4 Answers

Inspired from Yoav's answer. This code works for recyclerview item types and probably regardless of it's size.

It was tested with a recyclerview having linearlayout manager and three item types. Yet to check it 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;
    }
like image 73
Prasham Avatar answered Sep 21 '22 20:09

Prasham


Take the Screenshot of complete Recyclerview regardless of its items and item types:

This piece of code works like a charm.

Here is a clean way to do this 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();
like image 37
Nouman Ch Avatar answered Sep 22 '22 20:09

Nouman Ch


Here is my solution for LinearLayoutManager when all the items are on same size and there is only one type of item. This solution is based on This answer.

Note: It can possibly lead to out of 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 has originally been written in Kotlin. Here is the original code used by me.

like image 33
Yoav Sternberg Avatar answered Sep 18 '22 20:09

Yoav Sternberg


The best solution I found is

  1. create a new NestedScrollView

  2. add it to recyclerview's parent

  3. remove recyclerview from its parent "it's important to add it to a new parent"

  4. add recyclerview to nestedscrollview

  5. take screenshot of nestedscrollview

  6. add recyclerview to its main parent.

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

This method will return screenshot of 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;
            
            }

don't forget to recycle the bitmap after using it

like image 22
Momen Zaqout Avatar answered Sep 18 '22 20:09

Momen Zaqout