How to position icon position in materialbutton

Viewed 4525

I am using Materialbutton from the support library. I want the icon to be to the right of the text? Ican't seem to find how to do it. Any help is appreciated

6 Answers

You can use the app:iconGravity attribute.
Use the app:iconGravity="end" value.

enter image description here

If you used app:icon= and it was in the left side, when you make the layout RTL, it will show the icon from the RTL too.

LTR:

enter image description here

After changing the locale to a RTL one:

enter image description here

Which seems to be a normal behavior and it automatically does the job. However, you better add:

implementation 'com.google.android.material:material:1.0.0'

In your app build.gradle dependencies in order to use the latest MaterialButton which is better for this purpose.

I was also reading the documentation about MaterialButton from com.google.android.material.button.MaterialButton which mentioned:

Add icons to the start or center of this button of this button using the app:icon, app:iconPadding, app:iconTint, app:iconTintMode and app:iconGravity attributes.

But unfortunately, there weren't any attribute(s) wich would do the trick. Except app:iconGravity attribute which has start - textStart.

Solution:

Just add:

android:layoutDirection="rtl"

To your MaterialButton:

<com.google.android.material.button.MaterialButton
    android:id="@+id/guestLogin"
    style="@style/Widget.MaterialComponents.Button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@+id/relativeLayout"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="10dp"
    android:layoutDirection="rtl"
    android:text="@string/login_as_guest"
    android:textColor="@color/whiteColor"
    app:icon="@drawable/ic_keyboard_arrow_left_white_24dp" />

enter image description here


However, at the meantime, there was-were issue(s) in the documentation which I also created a pull request. Hope they'll fix the typo.

Add icons to the start or center of this button of this button

By the way, it could be better if they added end in app:iconGravity="" attribute.

There is no public API of MaterialButton that allows you to put the icon to the right of the text. This private method controls the drawing of the icon:

private void updateIcon() {
    if (this.icon != null) {
        this.icon = this.icon.mutate();
        DrawableCompat.setTintList(this.icon, this.iconTint);
        if (this.iconTintMode != null) {
            DrawableCompat.setTintMode(this.icon, this.iconTintMode);
        }

        int width = this.iconSize != 0 ? this.iconSize : this.icon.getIntrinsicWidth();
        int height = this.iconSize != 0 ? this.iconSize : this.icon.getIntrinsicHeight();
        this.icon.setBounds(this.iconLeft, 0, this.iconLeft + width, height);
    }

    TextViewCompat.setCompoundDrawablesRelative(this, this.icon, (Drawable)null, (Drawable)null, (Drawable)null);
}

If you aren't using app:iconGravity, though, you can sort of hack around this by manually changing the button's compound drawables after your layout is inflated:

Button b = findViewById(R.id.button);
Drawable d = TextViewCompat.getCompoundDrawablesRelative(b)[0]; // the start drawable
TextViewCompat.setCompoundDrawablesRelative(b, null, null, d, null); // move it to the end

A layout only approach to do this would be:

If you are using the support library

implementation 'com.android.support:design:28.0.0'

you can try

<android.support.v7.widget.AppCompatButton
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawableRight="@android:drawable/ic_menu_camera"
    android:text="Camera" />

If you are using the newer material ui library

implementation 'com.google.android.material:material:1.0.0'

you can try

<androidx.appcompat.widget.AppCompatButton
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:drawableRight="@android:drawable/ic_menu_camera"
    android:text="Camera" />

Try adding padding to start and to end. You should be able to position icons with that. E.g:

<androidx.appcompat.widget.AppCompatButton
                        android:id="@+id/fai_btn_dislike"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="16dp"
                        android:paddingLeft="16dp"
                        android:paddingRight="16dp"
                        android:layout_weight="1"
                        android:background="@drawable/btn_rounded"
                        android:drawableStart="@drawable/ic_thumb_down"
                        android:text="@string/fai_dislike"
                        app:icon="@drawable/ic_thumb_down" />

If you're looking for material button with only an icon, just copy this class and use it:

/**
 * Created by osapps on 1/20/21.
 *
 * This is a simple class of a material button with just an icon. You can set whatever you want in the xml to use this, but just make sure to also
 * the button's insetTop, insetBottom, insetLeft and insetRight to 0.
 */
class MaterialIconButton : MaterialButton {

    // indications
    private var absPropsSet = false

    constructor(context: Context) : super(context) {
        commonInit()
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        commonInit()
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        commonInit()
    }

    private fun commonInit() {
        setBackgroundColor(Color.TRANSPARENT)
        strokeWidth = 0
        stateListAnimator = null
        iconTintMode = PorterDuff.Mode.MULTIPLY
        iconGravity = ICON_GRAVITY_TEXT_START
        iconPadding = 0
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        if(!absPropsSet) {
            iconSize = measuredWidth - paddingStart
        }
    }

    /**
     * Will set absolute properties for the button. Call this function to make the button look exactly as you want.
     * NOTICE: don't forget to set, in the xml, the button's insetTop, insetBottom, insetLeft and insetRight to 0.
     */
    fun setAbsProps(iconSize: Int, @DimenRes paddingRes: Int? = null) {
        absPropsSet = true
        var padding = 0
        paddingRes?.apply { padding = resources.getDimensionPixelSize(paddingRes) }
        setPadding(0, 0, 0, 0)
        this.iconSize = iconSize
        layoutParams.width = iconSize + padding
        layoutParams.height = iconSize + padding
    }

}

Example of usage:

<com.osfunapps.remoteforsamsung.views.MaterialIconButton
            android:id="@+id/no_ads_btn"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_margin="12dp"

            android:insetLeft="0dp"
            android:insetTop="0dp"
            android:insetRight="0dp"
            android:insetBottom="0dp"
            android:padding="12dp"

            android:onClick="onNoAdsClick"
            app:icon="@drawable/ic_crown"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintWidth_percent="0.15"
            app:layout_constraintDimensionRatio="1:1"
            app:rippleColor="#F8CE36"
            />
Related