Is it possible to scale drawableleft & drawableright in textview?

AndroidTextview

Android Problem Overview


I have TextView with drawableLeft & drawableRight in List item. The problem is, whenever the height of TextView is larger, drawableLeft & drawableLeft didn't automatically scale based on the height of the TextView.

Is it possible to scale the height of drawableLeft & drawableRight in TextView ? (I was using 9 patch image)

textview drawableleft & drawableright's height problem

Android Solutions


Solution 1 - Android

This might help you out. There are two properties scaleX and scaleY

The code below will scale down the image and the text with 30%. Therefore you have to increase the font size with that many "sp", so that when it get re-sized (scaled) it would fit the "sp" you prefer.

Example. If I set the font to 18, then 30% out of 18 is 5.4sp, so roughly, this is the value I am targeting at, because when it gets scaled, it would become 13sp

<TextView
        android:textSize="18sp"
        android:scaleX="0.7"
        android:scaleY="0.7"

The last thing to do is set the CompundDrawable.

tview.setCompoundDrawablesWithIntrinsicBounds(getResources().getDrawable(R.drawable.xxx), null, null, null);

Solution 2 - Android

Wrap your resource in a drawable that defines your desired size similar to:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

  <item
      android:drawable="@drawable/icon"
      android:width="@dimen/icon_size"
      android:height="@dimen/icon_size" />

</layer-list >

After that, use this drawable in your textview tag

Solution 3 - Android

I solved an equivalent usecase by introducing a ScaleDrawable and overriding its .getIntrisicHeight() so that it is at least the TextView height. The TextView.addOnLayoutChangeListener part, required to rebind the Drawable on a TextView size change works with API11+

Drawable underlyingDrawable = 
        new BitmapDrawable(context.getResources(), result);

// Wrap to scale up to the TextView height
final ScaleDrawable scaledLeft = 
        new ScaleDrawable(underlyingDrawable, Gravity.CENTER, 1F, 1F) {
	// Give this drawable a height being at
	// least the TextView height. It will be
	// used by
	// TextView.setCompoundDrawablesWithIntrinsicBounds
	public int getIntrinsicHeight() {
		return Math.max(super.getIntrinsicHeight(), 
                        competitorView.getHeight());
	};
};

// Set explicitly level else the default value
// (0) will prevent .draw to effectively draw
// the underlying Drawable
scaledLeft.setLevel(10000);

// Set the drawable as a component of the
// TextView
competitorView.setCompoundDrawablesWithIntrinsicBounds(
        scaledLeft, null, null, null);

// If the text is changed, we need to
// re-register the Drawable to recompute the
// bounds given the new TextView height
competitorView.addOnLayoutChangeListener(new OnLayoutChangeListener() {

	@Override
	public void onLayoutChange(View v, int left, int top, int right, 
            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
		competitorView.setCompoundDrawablesWithIntrinsicBounds(scaledLeft, null, null, null);
	}
});

Solution 4 - Android

Hope this help

Textview tv = (TextView) findViewById(R.id.tv_dummy)
int imageResource =  R.mipmap.ic_image;
Drawable drawable = ContextCompat.getDrawable(context, imageResource);
int pixelDrawableSize = (int)Math.round(tv.getLineHeight() * 0.7); // Or the percentage you like (0.8, 0.9, etc.)
drawable.setBounds(0, 0, pixelDrawableSize, pixelDrawableSize); // setBounds(int left, int top, int right, int bottom), in this case, drawable is a square image
tv.setCompoundDrawables(
 null, //left
 null, //top
 drawable, //right
 null //bottom
);

Solution 5 - Android

The only acceptable answer here should be to use an ImageView with the scaleTypes as per usual. Hacky work arounds to scale an image on a TextView that isn't supported by Android seems.. unnecessary. Use the SDK as it was intended.

Solution 6 - Android

I did not found way. But that you show looks like a list of items. Each item would be a LinearLayout horizontal with imagesView from left to right and text in center. The image dimension do a android:scaleType="fitXY" for ajust the size height to the textview height. If you want no deform de image use scaleType="CENTER_INSIDE". http://developer.android.com/reference/android/widget/ImageView.ScaleType.html

<LinearLayout
     android:layout_width="fill_parent"
     android:id="@+id/HeaderList" 
     android:layout_gravity="top"
     android:layout_height="wrap_content" >  


     <ImageView
         android:id="@+id/backImg"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:layout_centerInParent="true"
         android:adjustViewBounds="true"
         android:background="@color/blancotransless"
         android:src="@drawable/header"
         android:scaleType="fitXY" >
     </ImageView>

         <TextView 
             android:layout_height="wrap_content"
             android:layout_width="wrap_content" 
             android:id="@+id/NameText"
             android:text="The time of prayer" 
             android:textColor="#FFFFFF"
             android:textSize="30sp" 
             android:layout_alignParentLeft="true"
             android:layout_alignParentTop="true" 
             android:paddingLeft="4dp"
             android:paddingTop="4dp" 
             />
    <ImageView
         android:id="@+id/backImg"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:layout_centerInParent="true"
         android:adjustViewBounds="true"
         android:background="@color/blancotransless"
         android:src="@drawable/header"
         android:scaleType="fitXY" >
     </ImageView>

</LinearLayout> 

Solution 7 - Android

Another approach to create a custom size for the drawable inside the TextView is by using the BindingAdapter. Using this, you will be able to set you image size in your xml.

For example, TextViewBindingAdapter.java

public class TextViewBindingAdapter {
    @BindingAdapter({"android:imageSize"})
    public static void bindIconSize(TextView textView, int size) {
        Drawable[] drawables = textView.getCompoundDrawables();
        if(drawables[0] != null) {
            drawables[0].setBounds(0, 0, size, size); // setBounds(int left, int top, int right, int bottom), in this case, drawable is a square image
            textView.setCompoundDrawables(
                    drawables[0], //left
                    null, //top
                    null, //right
                    null //bottom
            );
        }
        if(drawables[1] != null) {
            drawables[1].setBounds(0, 0, size, size); // setBounds(int left, int top, int right, int bottom), in this case, drawable is a square image
            textView.setCompoundDrawables(
                    null, //left
                    drawables[1], //top
                    null, //right
                    null //bottom
            );
        }
        if(drawables[2] != null) {
            drawables[2].setBounds(0, 0, size, size); // setBounds(int left, int top, int right, int bottom), in this case, drawable is a square image
            textView.setCompoundDrawables(
                    null, //left
                    null, //top
                    drawables[2], //right
                    null //bottom
            );
        }
        if(drawables[3] != null) {
            drawables[3].setBounds(0, 0, size, size); // setBounds(int left, int top, int right, int bottom), in this case, drawable is a square image
            textView.setCompoundDrawables(
                    null, //left
                    null, //top
                    null, //right
                    drawables[3] //bottom
            );
        }


    }
}

Now, in your .xml you can set the android:imageSize.

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginEnd="8dp"
    android:drawableLeft="@drawable/alpha_s_circle"
    android:drawablePadding="4dp"
    android:gravity="center_vertical"
    android:textSize="16sp"
    android:imageSize="@{300}"/>

And don't forget to set in your gradle.build this code below:

android {
    ....
    buildFeatures {
	    dataBinding = true
    }
}

Solution 8 - Android

Just make 9-path background repeating this pattern.

And also it seems it will be better look in case the pattern will be applied to the list, not to individual item.

Solution 9 - Android

I think the cleanest solution would be to override TextView. Here's an example:

https://gist.github.com/hrules6872/578b52fe90c30c7445a2

I changed a bit:

private void resizeCompoundDrawables() {
    Drawable[] drawables = getCompoundDrawables();
    if (compoundDrawableWidth > 0 || compoundDrawableHeight > 0) {
        for (Drawable drawable : drawables) {
            if (drawable == null) continue;

            Rect realBounds = drawable.getBounds();

            float drawableWidth = realBounds.width();
            if(this.compoundDrawableWidth>0)
                drawableWidth = this.compoundDrawableWidth;
            float drawableHeight = realBounds.height();
            if(this.compoundDrawableHeight>0)
                drawableHeight = this.compoundDrawableHeight;

            realBounds.right = realBounds.left + Math.round(drawableWidth);
            realBounds.bottom = realBounds.top + Math.round(drawableHeight);

            drawable.setBounds(realBounds);
        }
    }
    super.setCompoundDrawables(drawables[0], drawables[1], drawables[2], drawables[3]);
}

This way you can set the size of the drawable but if you care about width/height ratio make it the way suits you.

Now if you want it to automatically match height of the textview you may also override the TextView's method onSizeChanged:

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    compoundDrawableHeight = h;
    resizeCompoundDrawables();
}

You my also want to declare sizes for each side, for example leftCompoundDrawableWidth, rightCompoundDrawableWidth and so on.

Note that it does not work with a Shape as drawable. Sounds like TextView only accepts it if it has the size attributes, that way one can implement it by updating the size of the shapedrawable using setSize or setIntrinsicWidth or ... Not tested.

Solution 10 - Android

Maybe it's worth look at ImageSpan. It's a span that replaces the text it's attached to with a Drawable that can be aligned with the bottom or with the baseline of the surrounding. I think it will automatically scale it as well based on the height of the textview.

https://developer.android.com/reference/android/text/style/ImageSpan

Solution 11 - Android

I Tried all the solutions but none of them worked for me, then I tried this one

in TextView

           <TextView
            android:gravity="left"
            android:id="@+id/product_view_count"
            android:text="@string/view_product_count"
            android:drawableLeft="@drawable/ic_eye"
            android:drawablePadding="2dp"
            android:drawableTint="@color/orange"
            android:textSize="20sp"
            android:textColor="@color/orange"
            android:textStyle="bold"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

in your Activity or fragment or Adapter. I am using my adapter like this

viewcount=itemView.findViewById(R.id.product_view_count);

holder.viewcount.setPivotX(0);
holder.viewcount.setPivotY(0);
holder.viewcount.setScaleX(.7f);
holder.viewcount.setScaleY(.7f);

by using ScaleX, ScaleY in TextView text position will change. to keep the position in left/start using setPivotX,setPivotY

Thank's to Bö macht Blau for the nice solution here

Solution 12 - Android

The easiest is to create a new drawable and adjust the drawable objects size

 <vector xmlns:android="http://schemas.android.com/apk/res/android"
    **android:width="50dp"
    android:height="50dp"**
    android:viewportWidth="24"
    android:viewportHeight="24"
    android:tint="@android:color/white">
  <path
      android:fillColor="@android:color/black"
      android:pathData="M19,3H4.99C3.89,3 3,3.9 3,5l0.01,14c0,1.1 0.89,2 1.99,2h10l6,-6V5C21,3.9 20.1,3 19,3zM7,8h10v2H7V8zM12,14H7v-2h5V14zM14,19.5V14h5.5L14,19.5z"/>
</vector>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionhakimView Question on Stackoverflow
Solution 1 - AndroidkirilvView Answer on Stackoverflow
Solution 2 - AndroidShahrad ElahiView Answer on Stackoverflow
Solution 3 - AndroidblacelleView Answer on Stackoverflow
Solution 4 - AndroidJuan MarinView Answer on Stackoverflow
Solution 5 - AndroidmpellegrView Answer on Stackoverflow
Solution 6 - AndroidZeus MonoliticsView Answer on Stackoverflow
Solution 7 - AndroidMatheus Gagno BrunettiView Answer on Stackoverflow
Solution 8 - AndroidAndrew MatiukView Answer on Stackoverflow
Solution 9 - AndroidnavidView Answer on Stackoverflow
Solution 10 - AndroidSher SanginovView Answer on Stackoverflow
Solution 11 - AndroidAsesha GeorgeView Answer on Stackoverflow
Solution 12 - AndroidDereckChambokoView Answer on Stackoverflow