How to have Image and Text Center within a Button

后端 未结 12 2181
感动是毒
感动是毒 2020-12-02 15:48

I want to display TEXT and Icon on a Button.

+----------------------------+
|          Icon TEXT         |
+---------------------         


        
相关标签:
12条回答
  • 2020-12-02 16:06

    Similar to some other approaches, I think a good solution is to extend Button and add the missing functionality by overriding its onLayout method:

    public class CenteredIconButton extends Button {
        private static final int LEFT = 0, TOP = 1, RIGHT = 2, BOTTOM = 3;
    
        // Pre-allocate objects for layout measuring
        private Rect textBounds = new Rect();
        private Rect drawableBounds = new Rect();
    
        public CenteredIconButton(Context context) {
            this(context, null);
        }
    
        public CenteredIconButton(Context context, AttributeSet attrs) {
            this(context, attrs, android.R.attr.buttonStyle);
        }
    
        public CenteredIconButton(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }
    
        @Override
        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
            super.onLayout(changed, left, top, right, bottom);
    
            if (!changed) return;
    
            final CharSequence text = getText();
            if (!TextUtils.isEmpty(text)) {
                TextPaint textPaint = getPaint();
                textPaint.getTextBounds(text.toString(), 0, text.length(), textBounds);
            } else {
                textBounds.setEmpty();
            }
    
            final int width = getWidth() - (getPaddingLeft() + getPaddingRight());
    
            final Drawable[] drawables = getCompoundDrawables();
    
            if (drawables[LEFT] != null) {
                drawables[LEFT].copyBounds(drawableBounds);
                int leftOffset =
                        (width - (textBounds.width() + drawableBounds.width()) + getRightPaddingOffset()) / 2 - getCompoundDrawablePadding();
                drawableBounds.offset(leftOffset, 0);
                drawables[LEFT].setBounds(drawableBounds);
            }
    
            if (drawables[RIGHT] != null) {
                drawables[RIGHT].copyBounds(drawableBounds);
                int rightOffset =
                        ((textBounds.width() + drawableBounds.width()) - width + getLeftPaddingOffset()) / 2 + getCompoundDrawablePadding();
                drawableBounds.offset(rightOffset, 0);
                drawables[RIGHT].setBounds(drawableBounds);
            }
        }
    }
    

    The sample only works for left and right drawables, but could be extended to adjust top and bottom drawables too.

    0 讨论(0)
  • 2020-12-02 16:08

    How about using a SpannableString as the text with an ImageSpan?

    Button myButton = ...
    SpannableString ss = new SpannableString(" " + getString(R.string.my_button_text));
    Drawable d = getResources().getDrawable(R.drawable.myIcon);
    d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
    ImageSpan span = new ImageSpan(d, DynamicDrawableSpan.ALIGN_BOTTOM);
    ss.setSpan(span, 0, 1, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
    myButton.setText(ss);
    
    0 讨论(0)
  • 2020-12-02 16:08

    I made a custom component to solve this problem.

    Component class:

    class CustomImageButton @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyleAttr: Int = 0,
        defStyleRes: Int = 0
    ) : RelativeLayout(context, attrs, defStyleAttr, defStyleRes) {
    
        init {
            inflate(context, R.layout.custom_image_button, this)
    
            // Load the styled attributes and set their properties
            val typedArray = context.obtainStyledAttributes(
                attrs,
                R.styleable.CustomImageButton, defStyleAttr, 0
            )
    
            val src = typedArray?.getDrawable(R.styleable.CustomImageButton_cib_src)
            val text = typedArray?.getText(R.styleable.CustomImageButton_cib_text)
            val contentDescription = typedArray?.getText(R.styleable.CustomImageButton_cib_contentDescription)
    
            ivIcon.setImageDrawable(src)
            tvText.text = text
            ivIcon.contentDescription = contentDescription
    
            typedArray?.recycle()
        }
    }
    

    Component XML:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:toos="http://schemas.android.com/tools"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_width="fill_parent"
            android:layout_height="@dimen/button_height">
        <Button
                android:id="@+id/bClick"
                android:layout_height="wrap_content"
                android:layout_width="fill_parent"
                android:layout_alignTop="@+id/foreground"
                android:layout_alignBottom="@id/foreground"
                android:layout_alignEnd="@id/foreground"
                android:layout_alignStart="@id/foreground"/>
        <RelativeLayout
                android:id="@id/foreground"
                android:layout_width="fill_parent"
                android:layout_height="wrap_content">
            <TextView
                    android:id="@+id/tvText"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerInParent="true"
                    android:textColor="@color/textWhite"
                    toos:text="Some text to test"
                    toos:ignore="RelativeOverlap"/>
            <ImageView
                    android:id="@+id/ivIcon"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_toStartOf="@id/tvText"
                    android:paddingTop="1dip"
                    android:paddingBottom="1dip"
                    android:src="@mipmap/some_image_to_test"
                    toos:ignore="ContentDescription"/>
        </RelativeLayout>
    </RelativeLayout>
    

    The resources attributes, attrs.xml:

    <declare-styleable name="CustomImageButton">
            <attr name="cib_src" format="reference"/>
            <attr name="cib_text" format="string"/>
            <attr name="cib_contentDescription" format="string"/>
        </declare-styleable>
    

    Component use example:

    <app.package.components.CustomImageButton
                android:id="@+id/cibMyImageButton"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                android:layout_height="wrap_content"
                android:layout_width="match_parent"
                app:cib_src="@mipmap/my_image_to_put_in_the_button"
                app:cib_text="Some text to show in the button"
               app:cib_contentDescription="icon description"/>
    
    0 讨论(0)
  • 2020-12-02 16:13

    How about this one?

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/lovely_color"
        android:clickable="true"
        android:onClick="clickHandler">
    
           <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="no?"
                android:textColor="@color/white"
                android:layout_centerHorizontal="true"
                android:drawableLeft="@drawable/lovely_icon"
                android:drawablePadding="10dp"
                android:padding="10dp"
                android:gravity="center"
                android:textSize="21sp"/>
    
    </RelativeLayout>
    
    0 讨论(0)
  • 2020-12-02 16:19

    This is what I did... It can be improved. The text is centered and the icon is to the left. So they both aren't centered as a group.

    public class CustomButton extends Button
    {
        Rect r = new Rect();
        private Drawable buttonIcon = null;
        private int textImageSeparation = 10;
    
        public CustomButton(Context context, AttributeSet attrs, int defStyle)
        {
            super(context, attrs, defStyle);
        }
    
        public CustomButton(Context context, AttributeSet attrs)
        {
            super(context, attrs);
        }
    
        public CustomButton(Context context)
        {
            super(context);
        }
    
        protected void onDraw(Canvas canvas)
        {
            super.onDraw(canvas);
    
    
            Drawable icon = getButtonIcon();
            if(icon != null)
            {
                int drawableHeight = icon.getIntrinsicHeight();
                int drawableWidth = icon.getIntrinsicWidth();
                if(icon instanceof BitmapDrawable)
                {
                    Bitmap bitmap = ((BitmapDrawable)icon).getBitmap();
                    drawableWidth = (int) AndroidScreenUtils.dipToPixels(bitmap.getWidth());
                    drawableHeight = (int) AndroidScreenUtils.dipToPixels(bitmap.getHeight());
                }
                else
                {
                    drawableWidth = (int) AndroidScreenUtils.dipToPixels(icon.getIntrinsicWidth());
                    drawableHeight = (int) AndroidScreenUtils.dipToPixels(icon.getIntrinsicHeight());
                }
                float textWidth = getLayout().getPaint().measureText(getText().toString());
                float left = ((getWidth() - textWidth) / 2) - getTextImageSeparation() - drawableWidth;
    
                int height = getHeight();
                int top = (height - drawableHeight) /2;
                int right = (int) (left + drawableWidth);
                int bottom = top + drawableHeight;
                r.set((int) left, top, right, bottom);
                icon.setBounds(r);
                icon.draw(canvas);
            }
        }
    
        private Drawable getButtonIcon()
        {
            return buttonIcon;
        }
    
        public void setButtonIcon(Drawable buttonIcon)
        {
            this.buttonIcon = buttonIcon;
        }
    
        private int getTextImageSeparation()
        {
            return textImageSeparation;
        }
    
        public void setTextImageSeparation(int dips)
        {
            this.textImageSeparation = (int) AndroidScreenUtils.dipToPixels(dips);
        }
    
    
    
    }
    
    0 讨论(0)
  • 2020-12-02 16:19
    <LinearLayout
            style="@style/Sonnen.Raised.Button.Transparent.LightBlueBorder"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="30dp"
            android:orientation="horizontal"
            android:padding="20dp">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:drawableLeft="@drawable/refresh"
                android:drawablePadding="10dp"
                android:drawableStart="@drawable/refresh"
                android:gravity="center"
                android:text="@string/generic_error_button_text"
                android:textColor="@color/dark_sky_blue"
                android:textSize="20sp"/>
    
        </LinearLayout>
    
    0 讨论(0)
提交回复
热议问题