Reputation: 99
Here is the drawable code:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:top="0dp" android:bottom="10dp">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/holo_blue_light" />
<stroke
android:width="1dp"
android:color="#40adc2" />
<corners android:radius="4dp" />
</shape>
</item>
<item android:gravity="center_horizontal|bottom">
<rotate
android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="75%"
android:pivotY="47%">
<shape android:shape="rectangle">
<solid android:color="@android:color/holo_blue_light" />
<size
android:height="20dp"
android:width="15dp"/>
</shape>
</rotate>
</item>
</layer-list>
And here are two pictures showing the issue:
The first image is the incorrect one in API 19 and the second image is the correct one in android 9
Tried searching everywhere couldn't find a solution.
Thanks in advance
Upvotes: 4
Views: 230
Reputation: 13019
The layer-list drawable looks bad for API level 19 because
<size android:height="20dp"
android:width="15dp"/>
for the small rectangle is ignored. (You can test this if you remove the rotation and let the rectangle with the rounded corners have a transparent color)
For older API levels you have to set values for android:top
, android:bottom
,
android:left
and android:right
. If you know the dimensions of the TextView
in advance, you can calculate the values as follows (unit is always dp):
For example if your TextView
has a width of 200dp and a height of 80dp:
<item
android:top="60dp" android:bottom="0dp"
android:left="90dp" android:right="90dp">
<rotate
android:fromDegrees="45"
android:toDegrees="45"
android:pivotX="75%"
android:pivotY="47%">
<shape android:shape="rectangle">
<solid android:color="@android:color/holo_blue_light" />
</shape>
</rotate>
</item>
Please note that if you use this approach you don't need to set the size or the gravity.
Sometimes one can't be sure about the size of the TextView
(e.g. because its content may vary across different languages or on different screens). In this case you can create a custom TextView
which will draw the bubble as its background:
class BubbleTextView(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : TextView(context, attrs, defStyleAttr) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
private val rectPath = Path()
private val trianglePath = Path()
private val rectF = RectF()
private val triangleSize = resources.getDimensionPixelSize(R.dimen.triangle_size_20dp).toFloat()
private val cornerRadius = resources.getDimensionPixelSize(R.dimen.corner_radius_4dp).toFloat()
constructor(context: Context?):this(context, null, 0)
constructor(context: Context?, attrs: AttributeSet?):this(context, attrs, 0)
init{
paint.style = Paint.Style.FILL
paint.color = Color.CYAN
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
val myWidth = (right - left).toFloat()
val myHeight = (bottom - top).toFloat()
val centerX = myWidth / 2f
val lowerEdgeY = myHeight * 0.8f
rectF.set(0f, 0f, myWidth, lowerEdgeY)
rectPath.addRoundRect(rectF,cornerRadius, cornerRadius, Path.Direction.CW )
val delta = triangleSize * 0.5f
trianglePath.moveTo(centerX - delta, lowerEdgeY)
trianglePath.lineTo(centerX + delta, lowerEdgeY)
trianglePath.lineTo(centerX, myHeight)
trianglePath.close()
}
override fun onDraw(canvas: Canvas?) {
canvas?.drawPath(rectPath, paint)
canvas?.drawPath(trianglePath, paint)
super.onDraw(canvas)
}
}
Upvotes: 1