3

After seeing many questions for this feature and attempting to follow the answers, I was left wondering if there was a clearer example to be had?

Edit: I was attempting to make a large button that had an image and text that where 'in the middle'. It had to behave as a button (StateList drawable) and the image/text pair should be grouped and centered (as a group)

2
  • I wanna know whether u want a text and image alongside each other or the text to be overlayed on the image Commented Dec 18, 2012 at 7:15
  • @Corey Scott if my given solution helps you to solve your problem then you can accept my solution. Thanks. Commented Jan 7, 2013 at 9:43

4 Answers 4

6

IF you like to have Button with image + text, then why don't you use CompoundDrawable?

For example:

enter image description here

Also check: How do I use a compound drawable instead of a LinearLayout that contains an ImageView and a TextView

Sign up to request clarification or add additional context in comments.

1 Comment

Similarly to my other comment this results in a different visual outcome that what I was intending. This approach does not allow you to move the image in from the edge and still preserve the larger hit box and visual up date on click.
2

In an attempt to save others some time, I offer this:

layout/some_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:id="@+id/menu_ok"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    <!-- StateList Drawable to make it look like a button -->
    android:background="@drawable/btn_std_holo_states"
    <!-- Required so you can click on it like a button -->
    android:clickable="true"    
    <!-- Recommended min height from the guidelines -->
    android:minHeight="48dp"    
    <!-- OnClickEvent definition -->
    android:onClick="onClickOk" >   

    <!-- Compound drawable of graphic and text -->
    <TextView
        android:id="@+id/txt_ok"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        <!-- Center both the graphic and text inside the button -->
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        <!-- Draw the graphic to the left of the text -->
        android:drawableLeft="@drawable/ic_ok"
        <!-- Space between the graphic and the text-->
        android:drawablePadding="16dp"
        <!-- ensures the text and graphic are both centered vertically -->
        android:gravity="center"
        <!-- Text of the button -->
        android:text="@android:string/ok"
        <!-- Change the font to match the standard button settings (optional) -->
        android:textAppearance="?android:attr/textAppearanceButton" />

</RelativeLayout>

drawable/btn_std_holo_states.xml (referenced above)

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

    <item android:drawable="@drawable/abs__btn_cab_done_pressed_holo_dark" android:state_pressed="true"/>
    <item android:drawable="@drawable/abs__btn_cab_done_focused_holo_dark" android:state_enabled="true" android:state_focused="true"/>
    <item android:drawable="@android:color/transparent" android:state_enabled="true"/>
    <item android:drawable="@android:color/transparent"/>

</selector>

NOTE: the different @drawable and @android:color settings here can be anything and are only provided to make a complete example

5 Comments

Why wrap a TextView in a RelativeLayout if you could just use a Button? Since Button extends TextView, it supports compound drawables without a problem. What you're proposing seems rather cumbersome and inefficient.
When you use a button the drawableLeft draws the graphic on the edge of the button. What I was looking for was something where the graphic was a lot more centralized. Yes, you can use margins/padding to move the drawable in but that effects the area of the button which leads to other problems
isn't it an overkill to use RelativeLayout plus TextView to just decorate a Button with an image? such decoration could be easly done with a custom Drawable - see my answer here
I havent had a chance to check but based on your answer I was wondering if I could add the background to the textview and remove the need for the relative layout
This causes a problem for large companies that have blind and low-vision users. The TalkBack accessibility feature won't include "button" in the description since it is a RelativeLayout
1

try this custom Drawable:

class BackgroundDrawable extends StateListDrawable {
    private StateListDrawable mDrawable;
    private Bitmap mBitmap;
    private Matrix mMatrix;
    private boolean mScale;
    private int mGravity;
    private int mDx;
    private int mDy;

    public BackgroundDrawable(StateListDrawable sld, Resources res, int resId, boolean scale, int gravity, int dx, int dy) {
        mDrawable = sld;
        mBitmap = BitmapFactory.decodeResource(res, resId);
        mMatrix =  new Matrix();
        mScale = scale;
        mGravity = gravity;
        mDx = dx;
        mDy = dy;
    }

    public static void setupBackground(View v, int resId, boolean scale, int gravity, int horizontalPadding, int verticalPadding) {
        Drawable d = v.getBackground();
        if (d instanceof StateListDrawable) {
            StateListDrawable sld = (StateListDrawable) d;
            Drawable drawable = new BackgroundDrawable(sld, v.getResources(), resId, scale, gravity, horizontalPadding, verticalPadding);
            v.setBackgroundDrawable(drawable);
        }
    }

    @Override
    protected boolean onStateChange(int[] stateSet) {
        invalidateSelf();
        return super.onStateChange(stateSet);
    }

    @Override
    protected void onBoundsChange(Rect bounds) {
        mDrawable.setBounds(bounds);
        Rect b = new Rect(bounds);
        b.inset(mDx, mDy);
        RectF src = new RectF(0, 0, mBitmap.getWidth(), mBitmap.getHeight());
        RectF dst = new RectF(b);
        float[] values = new float[9];
        if (mScale) {
            mMatrix.setRectToRect(src, dst, ScaleToFit.START);
        }
        mMatrix.getValues(values);
        float sx = values[Matrix.MSCALE_X];
        float sy = values[Matrix.MSCALE_Y];
        Rect outRect = new Rect();
        Gravity.apply(mGravity, (int) (src.width() * sx), (int) (src.height() * sy), b, outRect);
        mMatrix.postTranslate(outRect.left, outRect.top);
    }

    @Override
    public void draw(Canvas canvas) {
        int[] stateSet = getState();
        mDrawable.setState(stateSet);
        mDrawable.draw(canvas);
        canvas.drawBitmap(mBitmap, mMatrix, null);
    }
}

and how to use it:

Button b0 = (Button) findViewById(R.id.b0);
BackgroundDrawable.setupBackground(b0, R.drawable.ic_launcher, false, Gravity.BOTTOM | Gravity.RIGHT, 10, 5);
Button b1 = (Button) findViewById(R.id.b1);
BackgroundDrawable.setupBackground(b1, R.drawable.ic_launcher, false, Gravity.TOP, 0, 0);

Comments

0

Try this:

Drawable appImg = getApplicationContext().getResources().getDrawable( R.drawable.ic_launcher );
appImg.setBounds( 0, 0, appImg.getIntrinsicHeight(), appImg.getIntrinsicWidth() );

Button btn_ok = (Button) findViewById(R.id.ok);
btn_ok.setCompoundDrawables( null, null, appImg, null );

Hope it helps you.

Thanks.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.