Aligning drawableLeft with text of button

后端 未结 14 1969
长情又很酷
长情又很酷 2021-01-30 06:41

Here is my layout:

\"enter

The issue I\'m facing is with the drawable checkmark. H

相关标签:
14条回答
  • 2021-01-30 06:59

    I know it's a bit late, but if anyone looking for another answer, here is another way to add icon without the need to wrap button with a ViewGroup

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <Button
            android:id="@+id/btnCamera"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Click!"
            android:textAllCaps="false"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </android.support.constraint.ConstraintLayout>
    

    *need to set textAllCaps to false to make the spannable working


    class MainActivity : AppCompatActivity() {
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            val buttonLabelBuilder = SpannableStringBuilder(btnCamera.text)
            val iconDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_camera)
            iconDrawable?.setBounds(0, 0, btnCamera.lineHeight, btnCamera.lineHeight)
            val imageSpan = ImageSpan(iconDrawable, ImageSpan.ALIGN_BOTTOM)
    
            buttonLabelBuilder.insert(0, "i ")
            buttonLabelBuilder.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
    
            btnCamera.text = buttonLabelBuilder
        }
    }
    

    0 讨论(0)
  • 2021-01-30 07:01

    Here is a another solution:

         <LinearLayout
            android:id="@+id/llButton"
            android:layout_width="match_parent"
            style="@style/button_celeste"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <TextView
                style="@style/button_celeste"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:drawablePadding="10dp"
                android:clickable="false"
                android:drawableLeft="@drawable/icon_phone"
                android:text="@string/call_runid"/>
        </LinearLayout>
    

    and the event:

        LinearLayout btnCall = (LinearLayout) findViewById(R.id.llButton);
        btnCall.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                call(runid.Phone);
            }
        });
    
    0 讨论(0)
  • 2021-01-30 07:03

    There are several solutions to this problem. Perhaps the easiest on some devices is to use paddingRight and paddingLeft to move the image and text next to each other as below.

    Original button

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"
        android:layout_marginTop="16dp"
        android:text="@string/scan_qr_code"
        android:textColor="@color/colorPrimary"
        android:drawableLeft="@drawable/ic_camera"
        android:paddingRight="90dp"
        android:paddingLeft="90dp"
        android:gravity="center"
        />
    

    The problem here is on smaller devices this padding can cause unfortunate problems such as this:

    The other solutions are all some version of "build a button out of a layout an image and a textview". They work, but completely emulating a button can be tricky. I propose one more solution; "build a button out of a layout an image, a textview, and a button"

    Here's the same button rendered as I propose:

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:layout_marginEnd="32dp"
        android:layout_marginTop="16dp"
        android:gravity="center"
        >
        <Button
            android:id="@+id/scanQR"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/white_bg_button"
            />
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:elevation="10dp"
            >
            <ImageView
                android:id="@+id/scanImage"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginRight="8dp"
                android:src="@drawable/ic_camera"
                />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="@style/Base.TextAppearance.AppCompat.Button"
                android:text="@string/scan_qr_code"
                android:textColor="@color/colorPrimary"
                />
        </LinearLayout>
    </RelativeLayout>
    

    As you can see, the button is now within a relative layout, but it's text and drawableLeft are not part of the button, they are in a separate layout that's placed on top of the button. With this, the button still acts like a button. The gotchas are:

    1. The inner layout needs an elevation for newer versions of Android. The button itself has an elevation greater than the ImageView and TextView, so even though they are defined after the Button, they will still be "below" it in elevation and be invisible. Setting 'android:elevation' to 10 solves this.
    2. The textAppearance of the TextView must be set so that it has the same appearance as it would in a button.
    0 讨论(0)
  • 2021-01-30 07:03

    Another quite hacky alternative is to add blank spacer views with weight="1" on each side of the buttons. I don't know how this would affect performance.

        <View
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="1" />
    
    0 讨论(0)
  • 2021-01-30 07:05

    You can use <com.google.android.material.button.MaterialButton/> .
    https://material.io/develop/android/components/material-button/

    It finally allows setting the icon gravity.

     <com.google.android.material.button.MaterialButton
            android:layout_width="match_parent"
            android:layout_height="48dp"
            android:layout_marginStart="16dp"
            android:layout_marginEnd="16dp"
            android:gravity="center"
            android:text="Awesome button"
            app:icon="@drawable/your_icon"
            app:iconGravity="textStart" />
    
    0 讨论(0)
  • 2021-01-30 07:05
    public class DrawableCenterTextView extends TextView {
    
        public DrawableCenterTextView(Context context, AttributeSet attrs,
                int defStyle) {
            super(context, attrs, defStyle);
        }
    
        public DrawableCenterTextView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public DrawableCenterTextView(Context context) {
            super(context);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            Drawable[] drawables = getCompoundDrawables();
            if (drawables != null) {
                Drawable drawableLeft = drawables[0];
                Drawable drawableRight = drawables[2];
                if (drawableLeft != null || drawableRight != null) {
                    float textWidth = getPaint().measureText(getText().toString());
                    int drawablePadding = getCompoundDrawablePadding();
                    int drawableWidth = 0;
                    if (drawableLeft != null)
                        drawableWidth = drawableLeft.getIntrinsicWidth();
                    else if (drawableRight != null) {
                        drawableWidth = drawableRight.getIntrinsicWidth();
                    }
                    float bodyWidth = textWidth + drawableWidth + drawablePadding;
                    canvas.translate((getWidth() - bodyWidth) / 2, 0);
                }
            }
            super.onDraw(canvas);
        }
    }
    
    0 讨论(0)
提交回复
热议问题