user1659274
user1659274

Reputation:

android: fit height of DrawableLeft in a textView

I am trying to display a blue line next to a block of text, pretty much like this:

enter image description here

Here's my code:

<TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:drawableLeft="@drawable/blue_line" />

blue_line is a jpg file. a blue rectangle. it displays in its original size regardless of the text in the textview. how can i adjust its height dynamically according to the height of the text? like make it shorter when theres little amount of text and longer when there's more text....

Upvotes: 33

Views: 85716

Answers (9)

Tomislav Brabec
Tomislav Brabec

Reputation: 559

Unfortunately, setBounds was not working for me so I had to do a workaround.

// Turn wanted drawable to bitmap
Drawable dr = getResources().getDrawable(R.drawable.somedrawable);
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();

// I had a square image with same height and width so I needed only TextView height (getLineHeight)
int size = textView1.getLineHeight();
Drawable d = new BitmapDrawable(getResources(), Bitmap.createScaledBitmap(bitmap, size, size, true));
textView1.setCompoundDrawables(d, null, null, null);

// Now we can set some spacing between text and image
textView1.setCompoundDrawablePadding(10);

It is not the best solution regarding performance because new bitmap is created, but still works.

Upvotes: 2

guy.gc
guy.gc

Reputation: 3501

I Created a class that extends TextView, and resize the drawables in onPreDrawListener.

public class MyTextView extends AppCompatTextView {

    public MyTextView(Context context, AttributeSet attrs, int style) {
        super(context, attrs, style);
        fitCompoundDrawableToLineHeight();
    }

    private void fitCompoundDrawableToLineHeight() {
        OnPreDraw.run(this, () -> {
            final Drawable[] cd = getCompoundDrawables();
            Arrays.stream(cd)
                .filter(drawable -> drawable != null)
                .forEach(d -> d.setBounds(0, 0, getLineHeight(), getLineHeight()));
            setCompoundDrawables(cd[0], cd[1], cd[2], cd[3]);
        });
    }
}

// Convenience class that abstracts onPreDraw logic
public class OnPreDraw {
    public static void run(View view, Runnable task) {
        view.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                if (!view.getViewTreeObserver().isAlive()) {
                    return true;
                }
                view.getViewTreeObserver().removeOnPreDrawListener(this);
                task.run();
                return true;
            }
        });
    }
}

Upvotes: 0

vipul mittal
vipul mittal

Reputation: 17401

You can try doing it in code by setting bounds for the image

textView1.getViewTreeObserver()
        .addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            Drawable img = ActivityName.this.getContext().getResources().getDrawable(
                R.drawable.blue_line);
            img.setBounds(0, 0, img.getIntrinsicWidth() * textView1.getMeasuredHeight() / img.getIntrinsicHeight(), textView1.getMeasuredHeight());
            textView1.setCompoundDrawables(img, null, null, null);
            textView1.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
    });

Upvotes: 33

KyleZB
KyleZB

Reputation: 1

I abstract out this method. It works when the drawable is on the left of the TextView,dynamically scaling. If drawable is on the right side,this method doesn't work, needing to figure out why, but you can just directly use textView.setcompounddrawableswithintrinsicbounds() with the right-size Drawable resource

@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
public static void ajustCompoundDrawableSizeWithText(final TextView textView, final Drawable leftDrawable, final Drawable topDrawable, final Drawable rightDrawable, final Drawable bottomDrawable) {
    textView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
           if(leftDrawable != null){
               leftDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
           }
            if(topDrawable != null){
                topDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
            }
            if(rightDrawable != null){
                rightDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
            }
            if(bottomDrawable != null){
                bottomDrawable.setBounds(0, 0, (int)textView.getTextSize(), (int)textView.getTextSize());
            }
            textView.setCompoundDrawables(leftDrawable, topDrawable, rightDrawable, bottomDrawable);
                textView.removeOnLayoutChangeListener(this);
        }
    });
}

Upvotes: 0

Ali Mehrpour
Ali Mehrpour

Reputation: 613

You can draw a line with your desired height on drawable canvas and set as left drawable of your TextView. check this out:

public class FullHeightLineDrawable extends Drawable {
    private Paint mPaint;
    private int mHeight;

    public FullHeightLineDrawable(int height) {
        mPaint = new Paint();
        mPaint.setColor(CompatUtils.getColor(R.color.colorAccent));
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(15);

        mHeight = height;
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawLine(0, -mHeight, 0, mHeight, mPaint);
    }

    @Override
    public void setAlpha(int alpha) {
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
    }

    @Override
    public int getOpacity() {
        return 0;
    }
}

Usage:

final Drawable drawable = new FullHeightLineDrawable(getHeight());
mTextView.setTextColor(watchingColor);
mTextView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);

Upvotes: 1

Droid Chris
Droid Chris

Reputation: 3783

The best way to do this is to wrap your drawable in an xml drawable file and set it as a drawable in your text view as follows:

Drawable XML File:

<?xml version="1.0" encoding="utf-8"?>
<bitmap 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:scaleType="fitXY"
    android:src="@drawable/total_calories"/>

TextView in XML:

<TextView 
    android:id="@+id/title_total_cal"
    style="@style/title_stats_textview"
    android:drawableLeft="@drawable/total_calories_drawable"/>

Upvotes: 8

Rethinavel
Rethinavel

Reputation: 3952

Simply, Keep your image as 9patch drawable.

You can add android:drawableLeft="@drawable/checkmark" to your textview. You can also set drawablePadding to keep the textview organized.

android:drawableLeft="@drawable/button_icon"
android:drawablePadding="2dip"

Here is the link to create 9patch drawable

<TextView android:text="@string/txtUserName" 
android:id="@+id/txtUserName"
android:layout_width="160dip"
android:layout_height="60dip"
android:layout_gravity="center"
android:drawableLeft="@drawable/button_icon"
android:drawablePadding="2dip"
/>  

Upvotes: 2

user1955009
user1955009

Reputation:

You need to make a one horizontal XML layout that has the blue line left and a textview right. Than use that layout like an item and make a ListView of those items. Something like here, but a bit simpler

Upvotes: -1

Hamid Shatu
Hamid Shatu

Reputation: 9700

Try as below...

<RelativeLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:src="@drawable/btndr" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/imageView" />

</RelativeLayout>

Upvotes: 4

Related Questions