Search code examples
androidtextviewandroid-custom-viewcompound-drawables

Drawing background on TextView (not on its full width)


I would like to set a background drawable (or resource) on a TextView, not taking into account its compound drawable width (and paddings).

Getting the width of the compound (left one to be more precise), and its paddings should not be a problem, but the setting of the background on the width of the textview minus the width of the compound drawable (described above).

Should you have any advice on doing that, please let me know.

Here's the needed result: separator

PS. I thought about having a horizontal LinearLayout with an ImageView and TextView as its children, and having the background set on the textview only, but I am interested in having the same result with less Views (in this case, exactly one), if it is possible.


Solution

  • You could use a LayerDrawable which supports insets, for example:

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:left="dimension" android:right="dimension">
            <shape android:shape="rectangle">
                <solid android:color="color" />
            </shape>
        </item>
    </layer-list>
    

    If you want to change your Drawable dynamically you're better off writing your own Drawable class. The following DividerDrawable for instance draws a line to a given padding onto a white background:

    public class DividerDrawable extends Drawable {
    
        private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private float mDensity;
        private int mPaddingLeft = 0;
    
        public DividerDrawable(Context context) {
            mPaint.setColor(Color.BLACK);
            mDensity = context.getResources().getDisplayMetrics().density;
        }
    
        @Override
        public void draw(Canvas canvas) {
            int width = canvas.getWidth();
            int height = canvas.getHeight();
            canvas.drawColor(Color.WHITE);
            canvas.drawRect(mPaddingLeft, height - mDensity, width, height, mPaint);
        }
    
        @Override
        public void setAlpha(int alpha) {
    
        }
    
        @Override
        public void setColorFilter(ColorFilter colorFilter) {
    
        }
    
        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    
        public void setPaddingLeft(int paddingLeft) {
            if (mPaddingLeft != paddingLeft) {
                mPaddingLeft = paddingLeft;
                invalidateSelf();
            }
        }
    }
    

    To set the left padding based on your left CompoundDrawable you could do something like this:

    private void setBackground(TextView textView, DividerDrawable background) {
        Drawable drawableLeft = textView.getCompoundDrawables()[0];
        int paddingLeft = drawableLeft != null ?
                textView.getPaddingLeft() + drawableLeft.getIntrinsicWidth() + textView.getCompoundDrawablePadding() :
                textView.getPaddingLeft();
        background.setPaddingLeft(paddingLeft);
        textView.setBackground(background);
    }
    

    To make good use of all this call it like so:

        DividerDrawable dividerDrawable = new DividerDrawable(this);
        TextView textView = (TextView) findViewById(R.id.text);
        setBackground(textView, dividerDrawable);