android RadioButton button drawable gravity
Asked Answered
S

7

28

I am generating RadioButtons dynamically with

RadioButton radioButton=new RadioButton(context);  

LayoutParams layoutParams=new LayoutParams(radioWidth,radioHeight);
layoutParams.gravity=Gravity.CENTER;

radioButton.setLayoutParams(layoutParams);
radioButton.setGravity(Gravity.CENTER);

BitmapDrawable bitmap = ((BitmapDrawable)drawableResource);
bitmap.setGravity(Gravity.CENTER);

radioButton.setBackgroundDrawable(getResources().getDrawable(R.drawable.itabs_radio));
radioButton.setButtonDrawable(bitmap);

as you can see I am desperately trying to set gravity of button drawable to center, but without a reason its always center and left aligned, heres the reason- the default style of android radio button:

<style name="Widget.CompoundButton">
<item name="android:focusable">true</item> 
<item name="android:clickable">true</item>
<item name="android:textAppearance">?android:attr/textAppearance</item> 
<item name="android:textColor">?android:attr/textColorPrimaryDisableOnly</item> 
<item name="android:gravity">center_vertical|left</item> 
</style>

<style name="Widget.CompoundButton.RadioButton">
<item name="android:background">@android:drawable/btn_radio_label_background</item> 
<item name="android:button">@android:drawable/btn_radio</item> 
</style>

Is there any way I can align button drawable to center?

Shirtwaist answered 10/12, 2010 at 9:53 Comment(0)
S
68

According to CompoundButton.onDraw() source code it's always left-aligned.

(Note the line buttonDrawable.setBounds(0, y, buttonDrawable.getIntrinsicWidth(), y + height);)

You will have to derive a new class from RadioButton and override onDraw().

EXAMPLE ADDED LATER:

Ok, so here's what you do. Firstly, here's a layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<org.test.TestProj.RadioButtonCenter
    android:id="@+id/myview"
    android:layout_width="fill_parent" 
    android:layout_height="100dp" 
    android:layout_centerInParent="true"
    android:text="Button test"
    />
</RelativeLayout>

Secondly here's the custom-drawing RadioButtonCenter:

package org.test.TestProj;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.RadioButton;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;

public class RadioButtonCenter extends RadioButton {

    public RadioButtonCenter(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CompoundButton, 0, 0);
        buttonDrawable = a.getDrawable(1);
        setButtonDrawable(android.R.color.transparent);
    }
    Drawable buttonDrawable;


     @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);

            if (buttonDrawable != null) {
                buttonDrawable.setState(getDrawableState());
                final int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
                final int height = buttonDrawable.getIntrinsicHeight();

                int y = 0;

                switch (verticalGravity) {
                    case Gravity.BOTTOM:
                        y = getHeight() - height;
                        break;
                    case Gravity.CENTER_VERTICAL:
                        y = (getHeight() - height) / 2;
                        break;
                }

            int buttonWidth = buttonDrawable.getIntrinsicWidth();
            int buttonLeft = (getWidth() - buttonWidth) / 2;
            buttonDrawable.setBounds(buttonLeft, y, buttonLeft+buttonWidth, y + height);
                buttonDrawable.draw(canvas);
            }
        }   
}

Finally, here's an attrs.xml file you need to put in res/values so the code can get at platform-defined attributes.

<?xml version="1.0" encoding="utf-8"?>
<resources>    
     <declare-styleable name="CompoundButton">
        <attr name="android:button" />
    </declare-styleable>
</resources>
Squireen answered 10/12, 2010 at 10:20 Comment(17)
Can you provide a sample snippet ? I'm not able to figure it out!Shirtwaist
Yes its really worth of 1000s. But I am not accepting it since I approached it with according to me a simpler way. No disrespect. Thanx again!Shirtwaist
Thanks a bunch Shardul. Allow me to point out that your version has a custom constructor, does not use attributes properly, and therefore cannot be used as a drop-in replacement for RadioButton. Never mind. That's the last time I ever go to that kind of trouble.Squireen
Also, allow me to point out that I did answer your question: you subclass RadioButton.Squireen
instead of android.R.id.empty , define transparent color and use R.color.transparent instead, otherwise,InflateException get thrown but the real cause of it is android.content.res.Resources$NotFoundException: File from drawable resource ID #0x1020004Pelerine
Thanks Theo, but what do you mean by "define transparent color"??Hermanhermann
setButtonDrawable(android.R.color.transparent);Hunkers
Hi @ReubenScratton , i tried your solution , but i am getting error com.packagename.RadioButtonCenter fail to instantiate , may I know what is left ?Munt
@ReubenScratton how to change the images ?Munt
is there any way to get drawable and text both centre aligned of radio button? please check here https://mcmap.net/q/503080/-display-custom-drawable-and-text-in-center-of-radio-button/2624806Ferryman
I did find that in newer Targets, the call to super.onDraw() actually causes issues, and draws the image left justified, before your ondraw executes... this did not happen in lower targets, but started in higher targets, so food for thought.Vann
Excellent answer and in fact the only solution for this problem that works properly. It is a damn shame that you have to do things like this for such a simple task, though.Haitian
When using compile 'com.android.support:design:23.0.1' a.getDrawable(1); returns null. Using a.getDrawable(R.styleable.CompoundButton_android_button); works for me though.Diarmuid
When I set android:layout_height="wrap_content" on the button the button image is croped.Munmro
@ReubenScratton, how to use it to align text and left drawable to right of radiobuttonMcginley
on android 7.0. It not highlight when choose tab diff.Boisterous
I have filled a bug report with the solution issuetracker.google.com/u/1/issues/125138960 If you think this will be fixed, push google to fix it, thxTacye
D
8

Simple solution, you can add a background to RadioButton, or set background="@null", .

<RadioButton
                android:id="@+id/cp_rd_btn"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:background="@null"/>

updated:

<RadioGroup
                android:layout_width="fill_parent"
                android:layout_height="wrap_content"
                android:orientation="horizontal" >

                <RadioButton
                    android:layout_width="0dp"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:background="@null"
                    android:button="@null"
                    android:drawableTop="@drawable/account_coolme_selector"
                    android:gravity="center" />

                <RadioButton
                    android:layout_width="0dp"
                    android:layout_height="fill_parent"
                    android:layout_weight="1"
                    android:background="@null"
                    android:button="@null"
                    android:drawableTop="@drawable/account_qq_selector"
                    android:gravity="center"
                    />
            </RadioGroup>
Diocese answered 29/5, 2014 at 8:34 Comment(3)
this doesn't resolve the problem - the button of the radio will still be aligned to the leftGard
hoot, thanks for the effort - but still no. The task is to align the button object, you are using drawableTop. See the accepted answer - you need to implement a custom RadioButton to achieve this.Gard
Good, it's definitely an hack but it works. I had to have a radio button only with an image no text and the image needed to be centered. I just made textsize = 0 and got exactly what I needed +1Tholos
M
3

Based on @hoot answers, I had customised it to make both text and drawable to the center without using attars,

class RadioButtonCenter(context: Context, attrs: AttributeSet) : RadioButton(context, attrs) {
internal var buttonDrawable: Drawable? = null


init {
    buttonDrawable = CompoundButtonCompat.getButtonDrawable(this@RadioButtonCenter)

}

override fun onDraw(canvas: Canvas) {
    val iconHeight = buttonDrawable!!.intrinsicHeight
    val buttonWidth = buttonDrawable!!.intrinsicWidth

    val totalWidth =
        buttonWidth + paint.measureText(text.toString()) + paddingLeft + paddingRight + compoundDrawablePadding
    if (totalWidth >= width) {
        super.onDraw(canvas)
    } else {
        setButtonDrawable(android.R.color.transparent)

        val availableSpace = ((width - totalWidth) / 2).toInt()

        buttonDrawable!!.state = drawableState
        val height = height
        var yTop = 0
        val verticalGravity = gravity and Gravity.VERTICAL_GRAVITY_MASK
        when (verticalGravity) {
            Gravity.BOTTOM -> yTop = height - iconHeight
            Gravity.CENTER_VERTICAL -> yTop = (height - iconHeight) / 2
        }
        var rightWidth = availableSpace + buttonWidth

        buttonDrawable!!.setBounds(availableSpace, yTop, rightWidth, yTop + iconHeight)
        buttonDrawable!!.draw(canvas)

        rightWidth += compoundDrawablePadding

        val yPos = (height / 2 - (paint.descent() + paint.ascent()) / 2) as Float
        canvas.drawText(
            text.toString(),
            (rightWidth).toFloat(),
            yPos,
            paint
        )
    }
}

}

Mcginley answered 28/4, 2019 at 7:31 Comment(0)
H
2

Based on @Reprator answers.

JAVA version:

public class RadioButtonCentered extends AppCompatRadioButton {

  private Drawable buttonDrawable;


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

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

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




  @Override
  protected void onDraw(Canvas canvas) {
      if (buttonDrawable != null) {
        int iconHeight = buttonDrawable.getIntrinsicHeight();
        int buttonWidth = buttonDrawable.getIntrinsicWidth();
        int width = getWidth();
        float totalWidth = buttonWidth + getPaint().measureText(getText().toString()) + getPaddingLeft() + getPaddingRight() + getCompoundDrawablePadding();

        if (totalWidth >= width) { super.onDraw(canvas); }
        else {
            int yTop = 0;
            int height = getHeight();
            int availableSpace = (int) ((width - totalWidth) / 2);
            int verticalGravity = getGravity() & Gravity.VERTICAL_GRAVITY_MASK;
            int rightWidth = availableSpace + buttonWidth;

            switch (verticalGravity) {
                case Gravity.BOTTOM:
                    yTop = height - iconHeight;
                    break;
                case Gravity.CENTER_VERTICAL:
                    yTop = (height - iconHeight) / 2;
                    break;
            }

            setButtonDrawable(android.R.color.transparent);
            buttonDrawable.setState(getDrawableState());
            buttonDrawable.setBounds(availableSpace, yTop, rightWidth, yTop + iconHeight);
            buttonDrawable.draw(canvas);

            float yPos = (height / 2 - (getPaint().descent() + getPaint().ascent()) / 2);

            canvas.drawText(getText().toString(), ((float) (rightWidth + getCompoundDrawablePadding())), yPos, getPaint());
        }
    } else {buttonDrawable = CompoundButtonCompat.getButtonDrawable(this); invalidate();}
  }
}
Heterogenesis answered 25/2, 2020 at 12:26 Comment(0)
M
1

I also think this sounds like a bug since it's always left-aligned. In my case I solved the issue by setting android:minWidth="0dp" and android:layout_width="wrap_content", since Material components had set the android:minWidth to a width larger than the drawable width. If the RadioButton needs to be centered it can then be added to a container and thus no custom view needs to be implemented.

Here's an example of how it could look:

<FrameLayout
    android:layout_width="200dp"
    android:layout_height="200dp">

    <RadioButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:clickable="false"
        android:minWidth="0dp" />

 </FrameLayout>

However, be aware that the minimum width was set there for a reason, Material design used ?attr/minTouchTargetSize. So if you do like above, the container should maybe also be touchable.

Midwest answered 22/4, 2020 at 15:22 Comment(0)
R
0

<radiogroup android:paddingLeft = "20dp" android:background="@color/gray">

Basically - I have a horizontally aligned radio group, and by expanding the background color to the left 20dp (or whatever 1/2 of your width of radio button) it appears as if it's centered.

Rowan answered 10/2, 2015 at 5:47 Comment(0)
N
0

you need foreground. not background. see args for layout and set em programmatically:

<RadioButton>
    ...
    android:button="@null"
    android:foreground="@drawable/your_selector_for_center_drawable"
    android:background="@drawable/your_selector_for_background_drawable"
    android:foregroundGravity="center"
</RadioButton>
Nonentity answered 20/6, 2022 at 16:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.