I'm having a tough time getting this XML layout to BMP, found similar post here: Converting a view to Bitmap without displaying it in Android?
But nothing in there has helped me; my view.measuredWidth
tends to always be 0. I'm running this code from inside an Activity, passing applicationContext. I dont want to take a screenshot of activity loading the layout because i need this to scale properly since it will be printed as well.
val v = LayoutInflater.from(applicationContext).inflate(R.layout.invoice_generated_layout, null)
v.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
v.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
v.layout(0, 0, v.measuredWidth, v.measuredHeight)
val b = Bitmap.createBitmap(v.width, v.height, Bitmap.Config.ARGB_8888)
val c = Canvas(b)
v.draw(c)
Here is XML for invoice_generated_layout
(over simplified for debugging)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/root_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical"
android:textAlignment="center">
<ImageView
android:id="@+id/activity_invlayoutgen_dynamiclogo"
android:layout_width="wrap_content"
android:layout_height="65dp"
android:layout_gravity="center|center_horizontal|center_vertical"
android:visibility="visible"/>
<TextView
android:id="@+id/textView97"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fontFamily="@font/ocraextended"
android:gravity="center"
android:includeFontPadding="true"
android:letterSpacing="-0.01"
android:text="Hello World, this is just a test."
android:textAlignment="center"
android:textColor="#000000"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
I also tested with this code and it does generate bmp but now its blank.
val view = LayoutInflater.from(applicationContext).inflate(R.layout.invoice_generated_layout, null)
view.measure(
View.MeasureSpec.makeMeasureSpec(500, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(300, View.MeasureSpec.EXACTLY)
)
val width = view.measuredWidth
val height = view.measuredHeight
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
view.draw(canvas)
Is it possible that my layout size on the layout designer is bad? Any ideas on what could be happening here?
Note that I did get it to render something when trying different changes to code, but all i got was a long image with only 2px in width...
I figured this out, since i'm not rendering this layout in the activity itself i was trying to generate the bitmap on a layout not yet loaded.
The new changes listen on ViewTreeObserver
to ensure that the layout process is done before attempting to get the measurement off the layout.
Here is the new code that generates BMP off a view that is not loaded into an activity.
// Inflate the XML layout
val inflater = getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
val view = inflater.inflate(R.layout.invoice_generated_layout, null)
// Create a bitmap with arbitrary dimensions for now
var bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888)
// Create a canvas with the bitmap
val canvas = Canvas(bitmap)
// Add the view to a parent layout so that it gets laid out and measured properly
val parentLayout = FrameLayout(applicationContext)
parentLayout.addView(view)
// Add a ViewTreeObserver and lets wait for the layout to complete w/e it needs to do...
parentLayout.viewTreeObserver.addOnGlobalLayoutListener(
object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
// Remove the listener to prevent multiple calls...
parentLayout.viewTreeObserver.removeOnGlobalLayoutListener(this)
// Measure and layout the view
view.measure(
View.MeasureSpec.makeMeasureSpec(parentLayout.width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(parentLayout.height, View.MeasureSpec.EXACTLY)
)
view.layout(0, 0, view.measuredWidth, view.measuredHeight)
// Resize the bitmap with the measured dimensions
bitmap.recycle()
bitmap =
Bitmap.createBitmap(
view.measuredWidth,
view.measuredHeight,
Bitmap.Config.ARGB_8888
)
// Draw the view onto the canvas
canvas.setBitmap(bitmap)
view.draw(canvas)
// Extra code for me to save bitmap to device.
saveBitmap(bitmap)
}
}
)