Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting bitmap from layout gets the layout incomplete

I am using a custom TextView that draws the text vertical, a graph from MPAndroidCharts library and a textview on top of the graph. While it looks great on the screen, when I try to get a Bitmap of it so it can be shared as an image, the vertical text views get are not drawn completely.

My XML of the View is the following:

<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:id="@+id/clWeatherCharts">
        <TextView
            android:id="@+id/txtWeatherTitle"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:layout_margin="@dimen/margin_16dp"
            android:text="@string/temperature_registers"
            android:textAlignment="center"/>

            <com.shadows.naylapp.utils.VerticalTextView
                android:id="@+id/llYEnvironment"
                android:textColor="@color/colorBlack"
                android:textSize="14sp"
                android:layout_width="20dp"
                android:layout_height="0dp"
                android:text="Temperatura Superficial del Mar (Cº)"
                android:layout_margin="@dimen/padding_8dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="@id/lineWeatherChart"
                app:layout_constraintBottom_toBottomOf="@id/lineWeatherChart"
                />

        <com.github.mikephil.charting.charts.LineChart
            android:id="@+id/lineWeatherChart"
            android:layout_marginTop="@dimen/margin_16dp"
            android:layout_width="0dp"
            android:layout_height="300dp"
            app:layout_constraintEnd_toStartOf="@id/llYWindEnvironment"
            app:layout_constraintStart_toEndOf="@id/llYEnvironment"
            app:layout_constraintTop_toBottomOf="@id/txtWeatherTitle" />
        <LinearLayout
            android:id="@+id/llYWindEnvironment"
            android:layout_width="20dp"
            android:layout_height="0dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@id/lineWeatherChart"
            app:layout_constraintBottom_toBottomOf="@id/lineWeatherChart">

            <com.shadows.naylapp.utils.VerticalTextView
                android:textColor="@color/colorBlack"
                android:textSize="14sp"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:text="Velocidad del Viento (Km/hr)"
                />
        </LinearLayout>

    </androidx.constraintlayout.widget.ConstraintLayout>

I am using an extension function to create the bitmap which is the following:

fun View.getBitmapFromView(): Bitmap? {
val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
 canvas.drawColor(Color.WHITE)
 this.draw(canvas)
return bitmap
}

and I call it like this: clWeatherCharts.getBitmapFromView()

the following is an image of the screen on the app screen on the app with vertical text views complete

And the following is the bitmap which gets the vertical textviews cropped: screen with cropped vertical text views

The code for the vertical text view is the following:

class VerticalTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) {
private val topDown = gravity.let { g ->
    !(Gravity.isVertical(g) && g.and(Gravity.VERTICAL_GRAVITY_MASK) == Gravity.TOP)
}
private val metrics = BoringLayout.Metrics()
private var padLeft = 0
private var padTop = 0

private var layout1: Layout? = null

override fun setText(text: CharSequence, type: BufferType) {
    super.setText(text, type)
    layout1 = null
}

private fun makeLayout(): Layout {
    if (layout1 == null) {
        metrics.width = height
        paint.color = currentTextColor
        paint.drawableState = drawableState
        layout1 = BoringLayout.make(text, paint, metrics.width, Layout.Alignment.ALIGN_NORMAL, 2f, 0f, metrics, false, TextUtils.TruncateAt.MIDDLE, height - compoundPaddingLeft - compoundPaddingRight)
        padLeft = compoundPaddingLeft
        padTop = extendedPaddingTop
    }
    return layout1!!
}

override fun onDraw(c: Canvas) {
    //      c.drawColor(0xffffff80); // TEST
    if (layout == null)
        return
    c.withSave {
        if (topDown) {
            val fm = paint.fontMetrics
            translate(textSize - (fm.bottom + fm.descent), 0f)
            rotate(90f)
        } else {
            translate(textSize, height.toFloat())
            rotate(-90f)
        }
        translate(padLeft.toFloat(), padTop.toFloat())
        makeLayout().draw(this)
    }
}
}

I have already tried putting some padding on the textviews, or centering the text and it gets even more cropped when getting the bitmap.

Any help is appreciated!

like image 805
Mateo Hervas Avatar asked Oct 15 '22 23:10

Mateo Hervas


1 Answers

Solution

You can go through each child in a ConstraintLayout, then draw the child's content by using Bitmap.drawBitmap(Bitmap, int, int, Paint).

// Get bitmap from a View
fun View.getBitmapFromView(): Bitmap? {
    val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    draw(canvas)
    return bitmap
}

// Get bitmap from a ConstraintLayout
fun ConstraintLayout.getBitmapFromView(): Bitmap {
    val bitmap = Bitmap.createBitmap(this.width, this.height, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(bitmap)
    canvas.drawColor(Color.WHITE)

    for (i in 0 until childCount) {
        val child = getChildAt(i)
        val childBitmap = child.getBitmapFromView()
        if (childBitmap != null) {
            canvas.drawBitmap(childBitmap, child.left.toFloat(), child.top.toFloat(), null)
        }
    }

    return bitmap
}

Using from the code

clWeatherCharts.getBitmapFromView()
like image 74
Son Truong Avatar answered Oct 19 '22 01:10

Son Truong