androidcodehunter
androidcodehunter

Reputation: 21937

How to align drawableLeft to top instead center in android TextView?

In TextView I set drawableLeft where the drawable is showing from center. I need to align the drawableLeft with top inside TextView like this image.

enter image description here

Is it possible to achieve this?

Upvotes: 55

Views: 30419

Answers (7)

Goran Horia Mihail
Goran Horia Mihail

Reputation: 3645

Try like this:

class MyTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null
) : AppCompatTextView(context, style) {
    private val leftDrawable = ContextCompat.getDrawable(context, R.drawable.checkmark)

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
        setBulletPoint(compoundDrawables[0], canvas)
    }

    private fun setBulletPoint(drawableLeft: Drawable?, canvas: Canvas?) {
        if (!TextUtils.isEmpty(text)) {
            leftDrawable?.let { drlft ->
                if (lineCount == 1) {
                    setCompoundDrawablesWithIntrinsicBounds(drlft, null, null, null)
                } else {
                    val buttonWidth = drlft.intrinsicWidth
                    val buttonHeight = drlft.intrinsicHeight
                    val topSpace = abs(buttonHeight - lineHeight) / 2
           
                    drlft.setBounds(0, topSpace, buttonWidth, topSpace + buttonHeight)
                    canvas?.apply {
                        save()
                        drlft.draw(canvas)
                        restore()
                    }
                }
            }
        }
    }
}

Upvotes: 0

cesards
cesards

Reputation: 16329

I think it's even easier than all the answers above: You only need to do this:

public class TopGravityDrawable extends BitmapDrawable {

    public TopGravityDrawable(Resources res, Bitmap bitmap) {
        super(res, bitmap);
    }

    @Override
    public void draw(Canvas canvas) {
        int halfCanvas = canvas.getHeight() / 2;
        int halfDrawable = getIntrinsicHeight() / 2;
        canvas.save();
        canvas.translate(0, -halfCanvas + halfDrawable);
        super.draw(canvas);
        canvas.restore();
    }
}

And then

 final Bitmap bitmap = BitmapFactory.decodeResource(mTitle.getResources(), R.drawable.icon);
 icon = new TopGravityDrawable(mTitle.getResources(), bitmap);
 title.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);

Remember this only works properly with LEFT and RIGHT compound drawables

Upvotes: 10

Andrew Kelly
Andrew Kelly

Reputation: 2188

If you want a purely XML solution then you can use an inset drawable to re-position your desired drawable.

<?xml version="1.0" encoding="utf-8"?>
<inset
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/actual_image_to_be_shown"
    android:insetTop="-32dp" />

You might have to play around with the inset value depending on your scenario. Then just use this XML drawable in your TextView drawableLeft/Start definition.

Upvotes: 3

xzw happy
xzw happy

Reputation: 101

you can do like this:

public class DrawableTopLeftTextView extends TextView {

    public DrawableTopLeftTextView(Context context) {
        super(context);
    }

    public DrawableTopLeftTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DrawableTopLeftTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        if (!TextUtils.isEmpty(getText())) {

            Drawable[] drawables = getCompoundDrawables();

            if (drawables != null) {

                Drawable drawableLeft = drawables[0];

                if (drawableLeft != null) {

                    Paint.FontMetricsInt fontMetricsInt = getPaint().getFontMetricsInt();
                    Rect bounds = new Rect();
                    getPaint().getTextBounds((String) getText(), 0, length(), bounds);
                    int textVerticalSpace = Math.round(bounds.top - fontMetricsInt.top);
                    int offset = (getHeight() - drawableLeft.getIntrinsicHeight()) / 2 - textVerticalSpace - getPaddingTop() / 2;
                    drawableLeft.setBounds(0, -offset, drawableLeft.getIntrinsicWidth(), drawableLeft.getIntrinsicHeight() - offset);
                }
            }
        }
        super.onDraw(canvas);
    }
}

Upvotes: 5

Rahul M Mohan
Rahul M Mohan

Reputation: 293

Use SpannableString and ImageSpan to achieve this.

String msg=" "+"haii";
ImageSpan mImageSpan== new ImageSpan(mContext, R.drawable.icon);
SpannableString text = new SpannableString(msg);
text.setSpan(mImageSpan, 0, 1, 0);
mTextView.setText(text);

the extra space in the string variable is replaced by the icon.

Upvotes: 13

Reinier
Reinier

Reputation: 3876

See my answer here.

You can align a compound-Drawable to the top (or bottom) by creating a custom Drawable that wraps your Drawable, and then manipulate the drawing of your custom Drawable by overriding the method onDraw(Canvas).

The sample below is the simplest possible example. This aligns the image to the top, but you can also make it align to the bottom, left or right of the TextView by implementing the required logic in the onDraw(Canvas)-method. You might also want to build in a margin in the onDraw(Canvas), to make your design implementation pixel perfect.

Sample usage:

GravityCompoundDrawable gravityDrawable = new GravityCompoundDrawable(innerDrawable);
// NOTE: next 2 lines are important!
innerDrawable.setBounds(0, 0, innerDrawable.getIntrinsicWidth(), innerDrawable.getIntrinsicHeight());
gravityDrawable.setBounds(0, 0, innerDrawable.getIntrinsicWidth(), innerDrawable.getIntrinsicHeight());
mTextView.setCompoundDrawables(gravityDrawable, null, null, null);

Sample code:

public class GravityCompoundDrawable extends Drawable {

    // inner Drawable
    private final Drawable mDrawable;

    public GravityCompoundDrawable(Drawable drawable) {
        mDrawable = drawable;
    }

    @Override
    public int getIntrinsicWidth() {
        return mDrawable.getIntrinsicWidth();
    }

    @Override
    public int getIntrinsicHeight() {
        return mDrawable.getIntrinsicHeight();
    }

    @Override
    public void draw(Canvas canvas) {
        int halfCanvas= canvas.getHeight() / 2;
        int halfDrawable = mDrawable.getIntrinsicHeight() / 2;

        // align to top
        canvas.save();
        canvas.translate(0, -halfCanvas + halfDrawable);
        mDrawable.draw(canvas);
        canvas.restore();
    }
}

Upvotes: 8

Mayur Chudasama
Mayur Chudasama

Reputation: 474

Your can use by this way. May it can helpful you.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

<RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="100dp"
    android:layout_alignParentLeft="true"
    android:layout_alignParentTop="true" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic_launcher" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@+id/imageView1"
        android:text=" Text Text Text Text Text Text Text Text Text Text Text Text 
        Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text   Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text Text" />
</RelativeLayout>

Upvotes: 0

Related Questions