Take a screenshot of RecyclerView in FULL length

后端 未结 5 1540
南方客
南方客 2020-12-13 07:55

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 fun

相关标签:
5条回答
  • 2020-12-13 08:15

    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();
    
    0 讨论(0)
  • 2020-12-13 08:26

    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.

    0 讨论(0)
  • 2020-12-13 08:28

    I wrote a method to get a screenshot of a few 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'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;
    }
    
    0 讨论(0)
  • 2020-12-13 08:30

    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

    0 讨论(0)
  • 2020-12-13 08:35

    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;
        }
    
    0 讨论(0)
提交回复
热议问题