Reputation: 1290
I have a drawableStart
icon drawable in my Button
below but it doesn't scale correctly. What can i do to correct this?
<Button
android:id="@+id/show_in_map_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="8dp"
android:background="@drawable/round_details_button"
android:drawableStart="@drawable/location_btn"
android:drawableTint="@android:color/white"
android:fontFamily="@font/montserrat_medium"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:text="@string/show_in_map_button"
android:textColor="@android:color/white"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/place_description" />
P.S: I've seen a few posts regarding this issue that attempted to solve it in code using ScaleDrawable
, but that didn't work for me.
Upvotes: 4
Views: 1130
Reputation: 12118
To have drawable of your custom size in Button
or TextView
, you can create custom class like below with some stylable attributes:
create attrs.xml file in res -> values folder and create styleable like below:
<resources>
<declare-styleable name="DrawableButton">
<attr name="drawableSize" format="dimension" />
<attr name="drawableScale" format="float" />
</declare-styleable>
</resources>
Then create class named DrawableButton
like below:
class DrawableButton : AppCompatButton {
internal var drawableSize: Float? = null
internal var drawableScale: Float = 1F
constructor(context: Context?) : this(context, null)
constructor(context: Context?, attr: AttributeSet?) : this(context, attr, android.R.style.Widget_Button)
constructor(context: Context?, attr: AttributeSet?, defStyle: Int) : super(context, attr, defStyle) {
loadAttrs(context, attr)
initDrawablesForResize()
}
private fun loadAttrs(context: Context?, attrs: AttributeSet?) {
if (context != null && attrs != null) {
val typedArray: TypedArray? = context.obtainStyledAttributes(attrs, R.styleable.DrawableButton, 0, 0)
typedArray?.let { arr ->
for (index in 0 until arr.indexCount) {
assignValueToVariables(arr, index)
}
}
typedArray?.recycle()
}
}
private fun assignValueToVariables(arr: TypedArray, index: Int) {
val resourceId = arr.getIndex(index)
when (resourceId) {
R.styleable.DrawableButton_drawableSize -> {
drawableSize = arr.getDimension(resourceId, Math.min(measuredHeight, measuredWidth).toFloat())
}
R.styleable.DrawableButton_drawableScale -> {
drawableScale = arr.getFloat(resourceId, 1F)
}
else -> {
// Left out because "Unused"
}
}
}
private fun initDrawablesForResize() {
val size = compoundDrawablesRelative.size
val drawableList = ArrayList<Drawable?>(size)
for (index in 0 until size) {
val drawable = compoundDrawablesRelative[index]
if (drawable != null) {
if (drawableSize == null) {
drawableSize = Math.min(drawable.intrinsicHeight.times(drawableScale), drawable.intrinsicWidth.times(drawableScale))
}
drawable.setBounds(
0,
0,
drawableSize!!.toInt(),
drawableSize!!.toInt()
)
drawableList.add(index, drawable)
} else {
drawableList.add(index, null)
}
}
this.setCompoundDrawablesRelative(drawableList[0], drawableList[1], drawableList[2], drawableList[3])
}
override fun performClick(): Boolean {
super.performClick()
return true
}
}
Rebuild the project once and now you're ready to use this DrawableButton
class in your xml file like below:
<your_package_name_where_this_class_is.DrawableButton
android:id="@+id/show_in_map_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="32dp"
android:layout_marginEnd="8dp"
android:background="@drawable/round_details_button"
android:drawableStart="@drawable/location_btn"
android:drawableTint="@android:color/white"
android:fontFamily="@font/montserrat_medium"
android:paddingStart="15dp"
android:paddingEnd="15dp"
android:text="@string/show_in_map_button"
android:textColor="@android:color/white"
android:textSize="14sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/place_description" />
Now you can use drawableSize
or drawableScale
attributes from app:
or other custom namespace to scale your drawables in drawableStart
, drawableEnd
, drawableTop
or drawableBottom
. It works with both vectors as well as raster images.
Note : It doesn't work with drawableLeft & drawableRight, due to method
setCompoundDrawablesRelative()
which uses start and end attrs for drawables. To work with left and right drawables replace this method withsetCompoundDrawables()
method.
Upvotes: 0
Reputation: 1534
One possible solution would be to wrap your resource in a drawable and define the height and width there and then use that drawable in your android:drawableStart
attribute. This only works from API 23 and above, but it won't crash your app on API 21 for example though. You can take a look at the example below:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@drawable/location_btn"
android:width="@dimen/icon_size"
android:height="@dimen/icon_size" />
</layer-list>
Upvotes: 0
Reputation: 6263
There is an old approach that works for me.
I simply create bounds and set it to my button. This way any drawable I attach to my drawable takes the dimension of the bounds.
drawable.bounds = Rect(0, 0, 80, 80) // in this case, the drawable is going to be 80 x 80
button.setCompoundDrawables(drawable, null, null, null)
I hope this helps. Merry coding!
Upvotes: 3
Reputation: 1828
Have you tried this, You can scale your drawable like this.
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/logo"
android:scaleGravity="center_vertical|center_horizontal"
android:scaleHeight="80%"
android:scaleWidth="80%" />
You can also scale your drawable like this
android:scaleType="fitXY"
Upvotes: 0