0

when capturing the layout to a Bitmap, the non-RecyclerView parts of my layout appear correctly, but the RecyclerView content is missing, How can I correctly convert a layout containing a RecyclerView (with all items visible) into a single bitmap image in Android (Java)? I need the final image to include all visible and off-screen RecyclerView items along with other layout data.

java

private void data()
    {
        if (NetworkCheck.getInstance(this.getApplicationContext()).isOnline()) {
            DatabaseReference reference = FirebaseDatabase.getInstance().getReference().child(PendingBill).child(BillID).child("Items");

            FirebaseRecyclerOptions<BillItem> options = new FirebaseRecyclerOptions.Builder<BillItem>()
                    .setQuery(reference.orderByChild("billID").equalTo(BillID), BillItem.class)
                    .build();
            FirebaseRecyclerAdapter<BillItem, BillViewHolder> adapter =
                    new FirebaseRecyclerAdapter<BillItem, BillViewHolder>(options) {

                        @Override
                        protected void onBindViewHolder(@NonNull BillViewHolder holder, int position, @NonNull final BillItem model) {

                            Integer Countcal, TotalCal, PriceCal;
                            Countcal=model.getCount();
                            PriceCal=model.getItemTotal();
                            TotalCal=Countcal*PriceCal;
                            String CountcalStr= String.valueOf(Countcal),TotalCalStr= String.valueOf(TotalCal);

                            holder.proName.setText(model.getProductName());
                            holder.proRate.setText(model.getItemTotal().toString());
                            holder.proCount.setText(CountcalStr);
                            holder.proTotal.setText(TotalCalStr);
                            holder.itemView.setOnClickListener(new View.OnClickListener() {
                                @Override
                                public void onClick(View view) {
                                   Share();
                                }

                            });

                        }
                        @NonNull
                        @Override
                        public BillViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
                            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.item_list, viewGroup, false);
                            BillViewHolder holder = new BillViewHolder(view);
                            return holder;
                        }

                        @Override
                        public void onDataChanged() {

                            // jprog.setVisibility(getItemCount() == 0 ? View.VISIBLE : View.GONE);
                            prog.setVisibility(View.GONE);
                        }                        };

            recyclerview.setAdapter(adapter);
            adapter.startListening();
            adapter.notifyDataSetChanged();

        } else {
            Toast.makeText(this, "Oops.. Internet is not connected please Establish it First", Toast.LENGTH_LONG).show();

        }
    }
  private void Share( Bitmap h) {

        // Measure and layout the view
        int widthSpec = View.MeasureSpec.makeMeasureSpec(1080, View.MeasureSpec.EXACTLY);
        int heightSpec = View.MeasureSpec.makeMeasureSpec(1920, View.MeasureSpec.AT_MOST);
        billView.measure(widthSpec, heightSpec);
        billView.layout(0, 0, billView.getMeasuredWidth(), billView.getMeasuredHeight());

        // Convert to bitmap
        Bitmap bitmap = Bitmap.createBitmap(billView.getMeasuredWidth(), billView.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        billView.draw(canvas);

// Save bitmap as image file (PNG or JPEG)
        try {
            File imagesDir = new File(Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES).toString() + File.separator + "MyBill");

            if (!imagesDir.exists())
                imagesDir.mkdir();

            imageFile = new File(imagesDir, "Invoice" + ".png");
            FileOutputStream outputStream = new FileOutputStream(imageFile);
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
            outputStream.flush();
            outputStream.close();

            Toast.makeText(this, "Invoice image saved!", Toast.LENGTH_SHORT).show();

        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(this, "Error saving image!", Toast.LENGTH_SHORT).show();
        }
    }

output image(textview random data) enter image description here

0

1 Answer 1

0

So the best way I've found is to redraw it to a non recylcerview Layout for converting to bitmap or pdf or printing.

The problem is you have fixed your bitmap size a width and height, you then give the recyclerview the same width and a maximum height before items will be off screen and not drawn.

If you have more items than will fit in this fixed height they won't be drawn by a recyclerview.

You are also adjusting the same Layout you are using for drawing out screen to a different non screen size, it is best to create a new Layout specifically for display to a bitmap and not re-use the view your are displaying on the screen otherwise you most likely will have problems.

Thus your layout needs measuring with ` View.MeasureSpec.UNSPECIFIED` for the height mesureSpec to allow it to get as tall as it needs to display all items.

You could draw the items to a new recyclerview for "off screen" drawing but the additional complexity and benefits of a recyclerview of are wasted when you are drawing all the items, thus it is easier to draw to a plain LinearLayout.

With a LinearLayout you can also easily measure individual items adding them as you go, so you can create a new bitmap when the list gets too longer. This make is very easy to create multiple page invoices.
Creating multiple page invoices is a must if the invoices are going to be printed out.

As an example here https://github.com/Zardozz/RecyclerviewPdf/tree/master is demo app that draws to an "off screen" LinearLayout which works out when a new page is needed.

While this final output of this demo is a PDF file, the concept is the same as for Bitmap in that you need to know the full height of all items using ` View.MeasureSpec.UNSPECIFIED` before your create the Bitmap or PDF page, or if you want to limit your individual bitmap or pdf page size then you need to create the items individually and work out when you need a new Bitmap of PDF Page.

Note that all this drawing really needs to be done in the background to stop it freezing the UI.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.