I need to get the total height of the view to generate a PDF to know how many pages need to be drawn.
I need to generate a PDF using screen content, which has a ScrollView containing data from a database.
I created a test project for this, see the code below.
Even if I change the XML to add more images, this code always gives me the same number:
ViewTreeObserver vto2 = layout.getViewTreeObserver(); vto2.addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { layout.getViewTreeObserver() .removeOnGlobalLayoutListener(this); } else { layout.getViewTreeObserver() .removeGlobalOnLayoutListener(this); } int width = layout.getMeasuredWidth(); int height = layout.getMeasuredHeight(); } });
This is my code to generate PDF:
public void convertXmlToPdf() { PdfDocument document = new PdfDocument(); DisplayMetrics displayMetrics = new DisplayMetrics(); int viewWidth = 1080; int viewHeight = 1920; int numPagina = 1; View view = LayoutInflater.from(this).inflate(R.layout.main_activity, null); view.measure(View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels * numPagina, View.MeasureSpec.EXACTLY)); view.getMeasuredHeight(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { this.getDisplay().getRealMetrics(displayMetrics); } else this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); if(ViewCompat.isLaidOut(view)) { view.getHeight(); } view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels); Display display = getWindowManager().getDefaultDisplay(); Point m_size = new Point(); display.getSize(m_size); int m_height = m_size.y; **double totalPages = Math.ceil(Double.parseDouble(m_height + "") / Double.parseDouble(viewHeight + "")); //TODO <----- i can't get the real height number here** // double totalPages = 4; do { view = LayoutInflater.from(this).inflate(R.layout.main_activity, null); if(numPagina == 1) { view.measure(View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels * numPagina, View.MeasureSpec.EXACTLY)); } else { view.measure(View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels * numPagina + (displayMetrics.heightPixels * numPagina - displayMetrics.heightPixels), View.MeasureSpec.EXACTLY)); //If i don't do this the next pages don't start from where they need } view.layout(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels); // Create a new PdfDocument instance view.getMeasuredHeight(); PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(displayMetrics.widthPixels, displayMetrics.heightPixels, numPagina).create(); // Start a new page PdfDocument.Page page = document.startPage(pageInfo); // Get the Canvas object to draw on the page Canvas canvas = page.getCanvas(); // Create a Paint object for styling the view Paint paint = new Paint(); paint.setColor(Color.BLACK); // Draw the view on the canvas view.draw(canvas); // Finish the page document.finishPage(page); numPagina++; } while (numPagina <= totalPages); // Specify the path and filename of the output PDF file File downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); String fileName = "exampleXML.pdf"; File filePath = new File(downloadsDir, fileName); try { // Save the document to a file FileOutputStream fos = new FileOutputStream(filePath); document.writeTo(fos); document.close(); fos.close(); // PDF conversion successful Toast.makeText(this, "XML to PDF Conversion Successful", Toast.LENGTH_LONG).show(); } catch (IOException e) { e.printStackTrace(); // Error occurred while converting to PDF } }
This is my XML file:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" android:id="@+id/rootview"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:text="Learn to Create PDF" android:textStyle="bold" android:textColor="@color/black"/> <Button android:id="@+id/btnCreatePdf" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Create PDF" /> <Button android:id="@+id/btnXMLToPDF" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Convert XML View to PDF" /> <ScrollView android:layout_width="wrap_content" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="30px" android:text="1" android:textColor="@color/black" /> <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="360px" android:src="@drawable/logo_om" android:visibility="visible" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="30px" android:text="2" android:textColor="@color/black"/> <ImageView android:layout_width="wrap_content" android:layout_height="360px" android:src="@drawable/logo_om" android:visibility="visible" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="30px" android:text="3" android:textColor="@color/black"/> <ImageView android:layout_width="wrap_content" android:layout_height="360px" android:src="@drawable/logo_om" android:visibility="visible" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="30px" android:text="4" android:textColor="@color/black"/> <ImageView android:layout_width="wrap_content" android:layout_height="360px" android:src="@drawable/logo_om" android:visibility="visible" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="30px" android:text="5" android:textColor="@color/black" /> <ImageView android:layout_width="wrap_content" android:layout_height="360px" android:src="@drawable/logo_om" android:visibility="visible" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:padding="30px" android:text="FINAL DO DOCUMENTO" /> </LinearLayout> </ScrollView> </LinearLayout>
@edit: Here are the links to what I've tried: Android: Total height of ScrollView
How to tell when the layout is drawn?
@Edit2: Here is a tutorial for creating a PDF (it only generates 1 page, so the code to generate more pages is what I found around) https://www.youtube.com/watch?v=-JC1PI-dSeE
The code always gives you the same number as you told It gives you whatever number it wants, and fixes the number to the size you tell it to give it.
When you set Measurespec to EXACTLY according to the documentation
So you are forcing the view size to an incorrect size calculated based on the screen size.
When drawing a PDF view, you can set the PDF page to an interesting size that matches your screen, or you can set it to a standard paper size, such as A4
If you choose non-standard width, you can also use non-standard height and only have one page. Then, if the user wanted to print it, they would have to split it into pages of multiple widths and heights. From a user perspective, there is no benefit to using multiple pages if you are just viewing the PDF on the screen
I think it's better to stick with the standard page size of the PDF, and then treat the PDF as a separate low-resolution screen, independent of the physical screen size of the device (they can scroll the page up, down, left, and right)
When you measure a single view, you are measuring the entire view and all its subviews, you cannot measure slices (what you want to see on the second and third pages).
There are two main ways to create multi-page PDFs from views.
Draw everything and then slice and dice it across multiple pages, using this approach you might have items that are split between pages, like the top half of certain lines of text on one page and The bottom half on another page makes it unreadable. This is not a good approach.
Iterate over the parent view's subviews, measure each subview, and add them to the layout of a single page. This way you can get the size of each subview and then calculate the cumulative size of all the views you've added to see if it's too big for your page size. If it's too big, you'll close the PDF page and start laying out to a new page. This means items are not split across pages (which is much better).
https://www.php.cn/link/ea89621bee7c88b2c5be6681c8ef4906 is a complete example of how to generate a multi-page PDF from a scrollable screen by measuring individual subviews (in this case, A scrollable screen is a recycling view, but you can iterate over the scroll view's children in a similar way).
Please note that A4 pages have a very low resolution, so the normal font size (or other item size) for the physical screen may be too large, so you will need to resize the layout for these as you normally would for different screen sizes). There is another way to resize a PDF page for low resolution, draw it to a multiple of the PDF page size, and then set the scale on the PDF canvas to scale it back to the correct size, e.g. draw to a layout that is twice as big, Then scale everything back to half size when drawing to the PDF page.
While the problem you may encounter is that your Textview may contain more text in a block than can fit on one page, these should require additional processing to create two Textviews instead of one.
The above is the detailed content of How to get the total height of a view. For more information, please follow other related articles on the PHP Chinese website!