【问题标题】:How to center icon and text in a android button with width set to "fill parent"如何将宽度设置为“填充父项”的android按钮中的图标和文本居中
【发布时间】:2011-04-07 17:53:02
【问题描述】:

我想要一个带有图标+文本的 Android Button。我正在使用 drawableLeft 属性来设置图像,如果按钮的宽度为"wrap_content",这很有效,但我需要拉伸到最大宽度,所以我使用宽度"fill_parent"。这会将我的图标直接移动到按钮的左侧,并且我希望图标和文本都在按钮内居中。

我已尝试设置填充,但这仅允许提供固定值,因此这不是我需要的。我需要在中心对齐图标+文本。

<Button 
    android:id="@+id/startTelemoteButton" 
    android:text="@string/start_telemote"
    android:drawableLeft="@drawable/start"
    android:paddingLeft="20dip"
    android:paddingRight="20dip"            
    android:width="fill_parent"
    android:heigh="wrap_content" />

关于如何实现这一目标的任何建议?

【问题讨论】:

  • 这可能没有简单的解决方案吗?我是否必须尝试使用​​带有图标的 9patch 按钮 img?
  • 这可能是一个解决方案。按钮文本是本地化的还是静态的?
  • 已本地化。没有其他解决方案吗?我设法用一个 9 补丁来做到这一点,但在更改语言环境时遇到了问题。
  • 如何使用带有可绘制 TOP 的 Button 并为其添加一些填充?
  • 糟糕的框架设计

标签: android android-layout user-interface button alignment


【解决方案1】:

android:drawableLeft 始终保持 android:paddingLeft 与左边框的距离。当按钮没有设置为android:width="wrap_content"时,它会一直挂在左边!

在 Android 4.0(API 级别 14)中,您可以使用 android:drawableStart 属性在文本开头放置一个可绘制对象。我想出的唯一向后兼容的解决方案是使用 ImageSpan 创建 Text+Image Spannable:

Button button = (Button) findViewById(R.id.button);
Spannable buttonLabel = new SpannableString(" Button Text");
buttonLabel.setSpan(new ImageSpan(getApplicationContext(), R.drawable.icon,      
    ImageSpan.ALIGN_BOTTOM), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
button.setText(buttonLabel);

在我的情况下,我还需要调整 Button 的 android:gravity 属性以使其看起来居中:

<Button
  android:id="@+id/button"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:minHeight="32dp"
  android:minWidth="150dp"
  android:gravity="center_horizontal|top" />

【讨论】:

  • 不错。最后一行应该是button.setText(buttonLabel)
  • Unicode 有大量与 Android 中的字符串兼容的字符图标。如果你能找到一个可以接受的解决方案,这是一个简单的解决方案,而且它还有一个额外的好处,那就是它会随文本大小缩放。例如,它有一个用于电子邮件图标的信封和几个不同的电话作为呼叫按钮。
  • 我很困惑这对任何人来说是如何工作的,对我来说它绘制了 2 个图标......一个向左,一个直接在中心显示在文本顶部。
  • drawableStart 不起作用。请参阅此线程:stackoverflow.com/questions/15350990/… 另外,似乎当您使用 spannable 设置文本时,样式会被忽略。
  • drawableStart 不起作用,在 API 级别 17 中添加以支持 rtl
【解决方案2】:

之前所有的答案似乎都已经过时了

您现在可以使用MaterialButton 来设置图标的重力。

 <com.google.android.material.button.MaterialButton
        android:id="@+id/btnDownloadPdf"
        android:layout_width="0dp"
        android:layout_height="56dp"
        android:layout_margin="16dp"
        android:gravity="center"
        android:textAllCaps="true"
        app:backgroundTint="#fc0"
        app:icon="@drawable/ic_pdf"
        app:iconGravity="textStart"
        app:iconPadding="10dp"
        app:iconTint="#f00"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:text="Download Pdf" />

为了使用材料组件,您显然需要:

添加依赖 implementation 'com.google.android.material:material:1.3.0-alpha01'(使用最新版本)

让您的主题扩展 Material Components 主题

<style name="AppTheme" parent="Theme.MaterialComponents.Light">
...
</style>

如果您不能这样做,请从 Material Bridge 主题扩展它

<style name="AppTheme" parent="Theme.MaterialComponents.Light.Bridge">
...
</style>

【讨论】:

  • 谢谢!你救了我的一天!工作正常
  • 不必更改整个应用程序主题,您可以通过在 MaterialButton 标签上使用 app:theme 只为按钮本身应用主题
【解决方案3】:

我知道我回答这个问题迟了,但这对我有帮助:

<FrameLayout
            android:layout_width="match_parent"
            android:layout_height="35dp"
            android:layout_marginBottom="5dp"
            android:layout_marginTop="10dp"
            android:background="@color/fb" >

            <Button
                android:id="@+id/fbLogin"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:background="@null"
                android:drawableLeft="@drawable/ic_facebook"
                android:gravity="center"
                android:minHeight="0dp"
                android:minWidth="0dp"
                android:text="FACEBOOK"
                android:textColor="@android:color/white" />
        </FrameLayout>

我从这里找到了这个解决方案:Android UI struggles: making a button with centered text and icon

【讨论】:

  • 这样的问题是按钮不是框架布局的宽度。
【解决方案4】:

我使用 LinearLayout 而不是 Button。我需要使用的 OnClickListener 也适用于 LinearLayout。

<LinearLayout
    android:id="@+id/my_button"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/selector"
    android:gravity="center"
    android:orientation="horizontal"
    android:clickable="true">

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="15dp"
        android:adjustViewBounds="true"
        android:scaleType="fitCenter"
        android:src="@drawable/icon" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="Text" />

</LinearLayout>

【讨论】:

    【解决方案5】:

    我通过左右添加padding来调整如下:

    <Button
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:id="@+id/btn_facebookact_like"
                android:text="@string/btn_facebookact_like"
                android:textColor="@color/black"
                android:textAllCaps="false"
                android:background="@color/white"
                android:drawableStart="@drawable/like"
                android:drawableLeft="@drawable/like"
                android:gravity="center"
                android:layout_gravity="center"
                android:paddingLeft="40dp"
                android:paddingRight="40dp"
                />
    

    【讨论】:

    • paddingLeft 和 paddingRight 帮助了我的居中。为简单的解决方案投票。
    • 如何处理宽度是动态的这一事实?如果旋转屏幕,所有图标都不会居中吗?我实际上正面临这个问题
    • 这是最好的答案!
    【解决方案6】:

    我最近遇到了同样的问题。试图找到一个更便宜的解决方案,所以想出了这个。

       <LinearLayout
            android:id="@+id/linearButton"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@drawable/selector_button_translucent_ab_color"
            android:clickable="true"
            android:descendantFocusability="blocksDescendants"
            android:gravity="center"
            android:orientation="horizontal" >
    
            <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:contentDescription="@string/app_name"
                android:src="@drawable/ic_launcher" />
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/app_name"
                android:textColor="@android:color/white" />
        </LinearLayout>
    

    然后只需在LinearLayout 上拨打OnClickListener

    希望这对某人有所帮助,因为这似乎是一个非常常见的问题。 :)

    【讨论】:

    • 这是一个好主意,但却是一个糟糕的解决方案。您可以使用 drawableLeft 属性仅使用一个 TextView 来实现相同的目的。这使您可以查看文本左侧的可绘制对象。
    • @muetzenflo 是的,没错。但是,当您使 textView 与父宽度匹配时,即使您将文本居中,您的可绘制对象也会移动到最左侧。如果我错了,请告诉我。问题只是关于这个。
    • 啊抱歉..我来这里就是为了这个问题,在尝试了太多东西后失去了注意力:) 猜猜我只见树木不见森林。我的错!
    【解决方案7】:

    您可以使用自定义按钮来测量和绘制自身以适应左侧可绘制对象。请查找示例和用法here

    public class DrawableAlignedButton extends Button {
    
        public DrawableAlignedButton(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public DrawableAlignedButton(Context context) {
        super(context);
    }
    
    public DrawableAlignedButton(Context context, AttributeSet attrs, int style) {
        super(context, attrs, style);
    }
    
    private Drawable mLeftDrawable;
    
    @Override
        //Overriden to work only with a left drawable.
    public void setCompoundDrawablesWithIntrinsicBounds(Drawable left,
            Drawable top, Drawable right, Drawable bottom) {
        if(left == null) return;
        left.setBounds(0, 0, left.getIntrinsicWidth(), left.getIntrinsicHeight());
        mLeftDrawable = left;
    }
    
    @Override
    protected void onDraw(Canvas canvas) {
        //transform the canvas so we can draw both image and text at center.
        canvas.save();
        canvas.translate(2+mLeftDrawable.getIntrinsicWidth()/2, 0);
        super.onDraw(canvas);
        canvas.restore();
        canvas.save();
        int widthOfText = (int)getPaint().measureText(getText().toString());
        int left = (getWidth()+widthOfText)/2 - mLeftDrawable.getIntrinsicWidth() - 2;
        canvas.translate(left, (getHeight()-mLeftDrawable.getIntrinsicHeight())/2);
        mLeftDrawable.draw(canvas);
        canvas.restore();
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = getMeasuredHeight();
        height = Math.max(height, mLeftDrawable.getIntrinsicHeight() + getPaddingTop() + getPaddingBottom());
        setMeasuredDimension(getMeasuredWidth(), height);
    }
    }
    

    用法

    <com.mypackage.DrawableAlignedButton
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:drawableLeft="@drawable/my_drawable"
            android:gravity="center"
            android:padding="7dp"
            android:text="My Text" />
    

    【讨论】:

    • 您可以在答案中包含代码,这应该是首选方式(如果不是太长的话),因为链接可能会随着时间的推移而失效-
    • 不是很准确,但我接受了
    • 它向右移动文本,但不够(图像与文本重叠)。此外,与其他自定义视图的解决方案一样,它不接受长文本。
    【解决方案8】:

    这是我 3 年前写的解决方案。按钮有文本和左图标,并且在框架中,这里是实际的按钮,可以通过 fill_parent 进行拉伸。我无法再次测试它,但它当时正在工作。可能 Button 不必使用,可以用 TextView 代替,但我现在不会测试它,它不会在这里改变太多功能。

    <FrameLayout
        android:id="@+id/login_button_login"
        android:background="@drawable/apptheme_btn_default_holo_dark"
        android:layout_width="fill_parent"
        android:layout_gravity="center"
        android:layout_height="40dp">
        <Button
            android:clickable="false"
            android:drawablePadding="15dp"
            android:layout_gravity="center"
            style="@style/WhiteText.Small.Bold"
            android:drawableLeft="@drawable/lock"
            android:background="@color/transparent"
            android:text="LOGIN" />
    </FrameLayout>
    

    【讨论】:

    • 现在我发现我并不孤单:)
    【解决方案9】:

    我知道这个问题有点老了,但也许你仍然愿意接受提示或解决方法:

    创建一个以按钮图像作为背景或按钮本身作为布局的第一个元素的RelativeLayout“wrap_content”。获取一个 LinearLayout 并将其设置为“layout_centerInParent”和“wrap_content”。然后将您的 Drawable 设置为 Imageview。最后用你的文本(语言环境)设置一个 TextView。

    所以基本上你有这个结构:

    RelativeLayout
      Button
        LinearLayout
          ImageView
          TextView
    

    或者像这样:

    RelativeLayout with "android-specific" button image as background
      LinearLayout
        ImageView
        TextView
    

    我知道这个解决方案有很多元素需要处理,但是您可以使用它轻松创建自己的自定义按钮,还可以设置文本和绘图的确切位置:)

    【讨论】:

    • 这种方法可以很好地工作。就我而言,我只需要一个包含 TextView 的 RelativeLayout。 RelativeLayout 获得了背景,TextView 获得了 drawableLeft 图标。然后在代码中:如果需要,将 onClickListener 附加到 RelativeLayout 和 findViewById 分别为 TextView
    • 第一个建议结构给出“Button cannot be cast to ViewGroup”异常。
    【解决方案10】:

    我解决这个问题的方法是用轻量级的&lt;View ../&gt; 元素包围按钮,这些元素可以动态调整大小。下面是几个例子,说明可以用这个实现什么:

    请注意,示例 3 中按钮的可点击区域与示例 2 中的相同(即带有空格),这与示例 4 中的按钮之间没有“不可点击”间隙不同。

    代码:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
        <TextView
            android:layout_marginStart="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="Example 1: Button with a background color:"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="20dp"
                android:paddingEnd="20dp"
                android:layout_weight="0.3"/>
            <!-- Play around with the above 3 values to modify the clickable 
                 area and image alignment with respect to text -->
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
        </LinearLayout>
    
        <TextView
            android:layout_marginStart="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="20dp"
            android:layout_marginBottom="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="Example 2: Button group + transparent layout + spacers:"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
        </LinearLayout>
    
        <TextView
            android:layout_marginStart="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="20dp"
            android:layout_marginBottom="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="Example 3: Button group + colored layout:"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/darker_gray">
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
            <Button
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <View
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="1"/>
        </LinearLayout>
    
        <TextView
            android:layout_marginStart="5dp"
            android:layout_marginLeft="5dp"
            android:layout_marginTop="20dp"
            android:layout_marginBottom="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textStyle="bold"
            android:text="Example 4 (reference): Button group + no spacers:"/>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/darker_gray">
            <Button
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <Button
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>
            <Button
                style="?android:attr/buttonBarButtonStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Button"
                android:textColor="@android:color/white"
                android:drawableLeft="@android:drawable/ic_secure"
                android:drawableStart="@android:drawable/ic_secure"
                android:background="@android:color/darker_gray"
                android:paddingStart="10dp"
                android:paddingEnd="10dp"
                android:layout_weight="1"/>   
        </LinearLayout>
    </LinearLayout>
    

    【讨论】:

      【解决方案11】:

      尝试使用这个库

      OmegaCenterIconButton

      【讨论】:

        【解决方案12】:

        您可以创建自定义小部件:

        Java 类 IButton:

        public class IButton extends RelativeLayout {
        
        private RelativeLayout layout;
        private ImageView image;
        private TextView text;
        
        public IButton(Context context) {
            this(context, null);
        }
        
        public IButton(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
        
        public IButton(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        
            LayoutInflater inflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            View view = inflater.inflate(R.layout.ibutton, this, true);
        
            layout = (RelativeLayout) view.findViewById(R.id.btn_layout);
        
            image = (ImageView) view.findViewById(R.id.btn_icon);
            text = (TextView) view.findViewById(R.id.btn_text);
        
            if (attrs != null) {
                TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.IButtonStyle);
        
                Drawable drawable = attributes.getDrawable(R.styleable.IButtonStyle_button_icon);
                if(drawable != null) {
                    image.setImageDrawable(drawable);
                }
        
                String str = attributes.getString(R.styleable.IButtonStyle_button_text);
                text.setText(str);
        
                attributes.recycle();
            }
        
        }
        
        @Override
        public void setOnClickListener(final OnClickListener l) {
            super.setOnClickListener(l);
            layout.setOnClickListener(l);
        }
        
        public void setDrawable(int resId) {
            image.setImageResource(resId);
        }
        

        }

        布局 ibutton.xml

        <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/btn_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clickable="true" >
        
        <ImageView
            android:id="@+id/btn_icon"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_marginRight="2dp"
            android:layout_toLeftOf="@+id/btn_text"
            android:duplicateParentState="true" />
        
        <TextView
            android:id="@+id/btn_text"
            android:layout_width="wrap_content"
            android:layout_height="fill_parent"
            android:layout_centerInParent="true"
            android:duplicateParentState="true"
            android:gravity="center_vertical"
            android:textColor="#000000" />
        </RelativeLayout>
        

        为了使用这个自定义小部件:

        <com.test.android.widgets.IButton
             android:id="@+id/new"
             android:layout_width="fill_parent"         
             android:layout_height="@dimen/button_height"
             ibutton:button_text="@string/btn_new"
             ibutton:button_icon="@drawable/ic_action_new" />
        

        您必须为自定义属性提供命名空间 xmlns:ibutton="http://schemas.android.com/apk/res/com.test.android.xxx" 其中 com.test.android.xxx 是应用的根包。

        只要把它放在 xmlns:android="http://schemas.android.com/apk/res/android" 下面。

        您最不需要的是 attrs.xml 中的自定义属性。

        在 attrs.xml 中

        <?xml version="1.0" encoding="utf-8"?>
        <resources>
        
            <declare-styleable name="IButtonStyle">
                <attr name="button_text" />
                <attr name="button_icon" format="integer" />
            </declare-styleable>
        
            <attr name="button_text" />
        
        </resources>
        

        为了更好的定位,如果您想避免RelativeLayout定位的潜在问题,请将自定义按钮包装在LinearLayout中。

        享受吧!

        【讨论】:

          【解决方案13】:

          有类似的问题,但希望有没有文本和没有包装布局的中心可绘制。解决方案是创建自定义按钮并在 LEFT、RIGHT、TOP、BOTTOM 之外再添加一个可绘制按钮。可以轻松地修改可绘制的位置并将其置于相对于文本的所需位置。

          CenterDrawableButton.java

          public class CenterDrawableButton extends Button {
              private Drawable mDrawableCenter;
          
              public CenterDrawableButton(Context context) {
                  super(context);
                  init(context, null);
              }
          
              public CenterDrawableButton(Context context, AttributeSet attrs) {
                  super(context, attrs);
                  init(context, attrs);
              }
          
              public CenterDrawableButton(Context context, AttributeSet attrs, int defStyleAttr) {
                  super(context, attrs, defStyleAttr);
                  init(context, attrs);
              }
          
              @TargetApi(Build.VERSION_CODES.LOLLIPOP)
              public CenterDrawableButton(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
                  super(context, attrs, defStyleAttr, defStyleRes);
                  init(context, attrs);
              }
          
          
              private void init(Context context, AttributeSet attrs){
                  //if (isInEditMode()) return;
                  if(attrs!=null){
                      TypedArray a = context.getTheme().obtainStyledAttributes(
                              attrs, R.styleable.CenterDrawableButton, 0, 0);
          
                      try {
                          setCenterDrawable(a.getDrawable(R.styleable.CenterDrawableButton_drawableCenter));
          
                      } finally {
                          a.recycle();
                      }
          
                  }
              }
          
              public void setCenterDrawable(int center) {
                  if(center==0){
                      setCenterDrawable(null);
                  }else
                  setCenterDrawable(getContext().getResources().getDrawable(center));
              }
              public void setCenterDrawable(@Nullable Drawable center) {
                  int[] state;
                  state = getDrawableState();
                  if (center != null) {
                      center.setState(state);
                      center.setBounds(0, 0, center.getIntrinsicWidth(), center.getIntrinsicHeight());
                      center.setCallback(this);
                  }
                  mDrawableCenter = center;
                  invalidate();
                  requestLayout();
              }
              @Override
              protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
                  super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                  if(mDrawableCenter!=null) {
                      setMeasuredDimension(Math.max(getMeasuredWidth(), mDrawableCenter.getIntrinsicWidth()),
                              Math.max(getMeasuredHeight(), mDrawableCenter.getIntrinsicHeight()));
                  }
              }
              @Override
              protected void drawableStateChanged() {
                  super.drawableStateChanged();
                  if (mDrawableCenter != null) {
                      int[] state = getDrawableState();
                      mDrawableCenter.setState(state);
                      mDrawableCenter.setBounds(0, 0, mDrawableCenter.getIntrinsicWidth(),
                              mDrawableCenter.getIntrinsicHeight());
                  }
                  invalidate();
              }
          
              @Override
              protected void onDraw(@NonNull Canvas canvas) {
                  super.onDraw(canvas);
          
                  if (mDrawableCenter != null) {
                      Rect rect = mDrawableCenter.getBounds();
                      canvas.save();
                      canvas.translate(getWidth() / 2 - rect.right / 2, getHeight() / 2 - rect.bottom / 2);
                      mDrawableCenter.draw(canvas);
                      canvas.restore();
                  }
              }
          }
          

          attrs.xml

          <resources>
              <attr name="drawableCenter" format="reference"/>
              <declare-styleable name="CenterDrawableButton">
                  <attr name="drawableCenter"/>
              </declare-styleable>
          </resources>
          

          用法

          <com.virtoos.android.view.custom.CenterDrawableButton
                      android:id="@id/centerDrawableButton"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      app:drawableCenter="@android:drawable/ic_menu_info_details"/>
          

          【讨论】:

          • 谢谢!这就是我一直在寻找的。​​span>
          • 你能帮我解决这个问题吗,stackoverflow.com/questions/35912539/…,你的回答我非常接近它,但出现了两个可绘制对象
          • 此解决方案将 drawable 放置在按钮的中心,就在居中的文本上方。
          【解决方案14】:

          如果你尝试 android:gravity="center_horizo​​ntal" 会发生什么?

          【讨论】:

          • 它不起作用。文本有点居中,但 drawableLeft 粘在左侧。
          • 太棒了。谢谢
          【解决方案15】:
          <style name="captionOnly">
              <item name="android:background">@null</item>
              <item name="android:clickable">false</item>
              <item name="android:focusable">false</item>
              <item name="android:minHeight">0dp</item>
              <item name="android:minWidth">0dp</item>
          </style>
          
          <FrameLayout
             style="?android:attr/buttonStyle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content" >
          
              <Button
                 style="@style/captionOnly"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
                 android:drawableLeft="@android:drawable/ic_delete"
                 android:gravity="center"
                 android:text="Button Challenge" />
          </FrameLayout>
          

          将 FrameLayout 放入 LinearLayout 并将方向设置为水平。

          【讨论】:

            【解决方案16】:

            您可以将按钮放在 LinearLayout 上

            <RelativeLayout
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/activity_login_fb_height"
                    android:background="@mipmap/bg_btn_fb">
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:gravity="center">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:id="@+id/lblLoginFb"
                            android:textColor="@color/white"
                            android:drawableLeft="@mipmap/icon_fb"
                            android:textSize="@dimen/activity_login_fb_textSize"
                            android:text="Login with Facebook"
                            android:gravity="center" />
                    </LinearLayout>
                    <Button
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:id="@+id/btnLoginFb"
                        android:background="@color/transparent"
                        />
                </RelativeLayout>
            

            【讨论】:

              【解决方案17】:

              我认为 android:gravity="center" 应该可以工作

              【讨论】:

              • 对我不起作用。它使文本居中,但 drawableLeft 仍位于最左侧。
              • 你必须在同一个父级下声明图标和文本,父级使用android:gravity = "centre"
              【解决方案18】:

              正如 Rodja 所建议的,在 4.0 之前,没有直接的方法可以将文本与可绘制对象居中。实际上,设置 padding_left 值确实会将可绘制对象从边框移开。因此我的建议是,在运行时,您可以准确计算出您的可绘制对象需要从左边框有多少像素,然后使用setPadding 传递它 您的计算可能类似于

              int paddingLeft = (button.getWidth() - drawableWidth - textWidth) / 2;
              

              你的drawable的宽度是固定的,你可以查看它,你也可以计算或猜测文本的宽度。

              最后,您需要将填充值乘以屏幕密度,您可以使用DisplayMetrics 来完成此操作

              【讨论】:

                【解决方案19】:

                公共类 DrawableCenterTextView 扩展 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);
                }
                

                }

                【讨论】:

                • 这对我根本不起作用。你能举个例子吗?也许我没有正确使用它
                【解决方案20】:

                脏修复。

                android:paddingTop="10dp"
                android:drawableTop="@drawable/ic_src"
                

                计算正确的填充解决了目的。但是,对于不同的屏幕,使用不同的填充并将其放在相应值文件夹中的维度资源中。

                【讨论】:

                  【解决方案21】:

                  使用 RelativeLayout(容器)和 android:layout_centerHorizo​​ntal="true" ,我的样本:

                                  <RelativeLayout
                                      android:layout_width="0dp"
                                      android:layout_height="match_parent"
                                      android:layout_weight="1" >
                  
                                      <CheckBox
                                          android:layout_width="wrap_content"
                                          android:layout_height="match_parent"
                                          android:layout_centerHorizontal="true"
                                          android:layout_gravity="center"
                                          android:layout_marginBottom="5dp"
                                          android:layout_marginLeft="10dp"
                                          android:layout_marginTop="5dp"
                                          android:button="@drawable/bg_fav_detail"
                                          android:drawablePadding="5dp"
                                          android:text=" Favorite" />
                                  </RelativeLayout>
                  

                  【讨论】:

                    【解决方案22】:

                    保留按钮主题的其他可能性。

                    <Button
                                android:id="@+id/pf_bt_edit"
                                android:layout_height="@dimen/standard_height"
                                android:layout_width="match_parent"
                                />
                    
                            <LinearLayout
                                android:layout_width="0dp"
                                android:layout_height="0dp"
                                android:layout_alignBottom="@id/pf_bt_edit"
                                android:layout_alignLeft="@id/pf_bt_edit"
                                android:layout_alignRight="@id/pf_bt_edit"
                                android:layout_alignTop="@id/pf_bt_edit"
                                android:layout_margin="@dimen/margin_10"
                                android:clickable="false"
                                android:elevation="20dp"
                                android:gravity="center"
                                android:orientation="horizontal"
                                >
                    
                                <ImageView
                                    android:layout_width="wrap_content"
                                    android:layout_height="match_parent"
                                    android:adjustViewBounds="true"
                                    android:clickable="false"
                                    android:src="@drawable/ic_edit_white_48dp"/>
                    
                                <TextView
                                    android:id="@+id/pf_tv_edit"
                                    android:layout_width="wrap_content"
                                    android:layout_height="match_parent"
                                    android:layout_marginLeft="@dimen/margin_5"
                                    android:clickable="false"
                                    android:gravity="center"
                                    android:text="@string/pf_bt_edit"/>
                    
                            </LinearLayout>
                    

                    如果您添加了这个解决方案 @color/你的颜色 @color/your_highlight_color 在您的活动主题中,您可以在 Lollipop 上使用带有阴影和波纹的 Matherial 主题,而对于以前版本的扁平按钮,您可以在按下它时使用您的颜色和高亮坐标。

                    此外,使用此解决方案自动调整图片大小

                    结果: 首先在棒棒糖设备上 第二:在棒棒糖设备上 3th : Pre lollipop device press button

                    【讨论】:

                      【解决方案23】:

                      我使用paddingLefttextView 与图标居中,并将textView 与left|centerVertical 对齐。对于视图和图标之间的小间隙,我使用了drawablePadding

                               <Button
                                  android:id="@+id/have_it_main"
                                  android:layout_width="match_parent"
                                  android:layout_height="wrap_content"
                                  android:background="@drawable/textbox"
                                  android:drawableLeft="@drawable/have_it"
                                  android:drawablePadding="30dp"
                                  android:gravity="left|center_vertical"
                                  android:paddingLeft="60dp"
                                  android:text="Owner Contact"
                                  android:textColor="@android:color/white" />
                      

                      【讨论】:

                      • 这不适用于许多屏幕,仅适用于 android:paddingLeft 工作的屏幕。
                      【解决方案24】:

                      这可能是一个旧的/关闭的线程,但我到处搜索都没有找到有用的东西,直到我决定创建自己的解决方案。如果这里有人试图寻找答案,试试这个,可能会节省你一分钟的思考时间

                                <LinearLayout
                                  android:id="@+id/llContainer"
                                  android:layout_width="match_parent"
                                  android:layout_height="match_parent"
                                  android:background="@drawable/selector"
                                  android:clickable="true"
                                  android:gravity="center"
                                  android:orientation="vertical"
                                  android:padding="10dp"
                                  android:textStyle="bold">
                      
                                  <TextView
                                      android:layout_width="wrap_content"
                                      android:layout_height="wrap_content"
                                      android:gravity="center"
                                      android:text="This is a text" />
                      
                                  <ImageView
                                      android:layout_width="wrap_content"
                                      android:layout_height="wrap_content"
                                      android:src="@drawable/icon_image />
                      
                      
                              </LinearLayout>
                      

                      因为线性布局充当容器并且拥有选择器,所以当您单击整个线性布局时,它看起来就是它应该的样子。如果您希望它都居中,请使用相对 insteaf。如果您希望它水平居中,请将方向更改为水平。

                      请注意不要忘记将 android:clickable="true" 添加到您的主容器(相对或线性)以执行操作。

                      同样,这可能是旧线程,但仍然可以帮助那里的人。

                      -干杯希望它有所帮助- 快乐编码。

                      【讨论】:

                        【解决方案25】:

                        如果您使用自定义视图的解决方案之一,请小心,因为它们经常在长或多行文本上失败。我重写了一些答案,替换了onDraw() 并理解这是错误的方式。

                        【讨论】:

                          【解决方案26】:

                          我已经看到了在开始/左侧对齐可绘制对象的解决方案,但对于可绘制对象结束/右侧却没有,所以我想出了这个解决方案。它使用动态计算的填充来对齐左右两侧的可绘制对象和文本。

                          class IconButton @JvmOverloads constructor(
                              context: Context,
                              attrs: AttributeSet? = null,
                              defStyle: Int = R.attr.buttonStyle
                          ) : AppCompatButton(context, attrs, defStyle) {
                          
                              init {
                                  maxLines = 1
                              }
                          
                              override fun onDraw(canvas: Canvas) {
                                  val buttonContentWidth = (width - paddingLeft - paddingRight).toFloat()
                          
                                  val textWidth = paint.measureText(text.toString())
                          
                                  val drawable = compoundDrawables[0] ?: compoundDrawables[2]
                                  val drawableWidth = drawable?.intrinsicWidth ?: 0
                                  val drawablePadding = if (textWidth > 0 && drawable != null) compoundDrawablePadding else 0
                                  val bodyWidth = textWidth + drawableWidth.toFloat() + drawablePadding.toFloat()
                          
                                  canvas.save()
                          
                                  val padding = (buttonContentWidth - bodyWidth).toInt() / 2
                                  val leftOrRight = if (compoundDrawables[0] != null) 1 else -1
                                  setPadding(leftOrRight * padding, 0, -leftOrRight * padding, 0)
                          
                                  super.onDraw(canvas)
                                  canvas.restore()
                              }
                          }
                          

                          根据您在哪里设置图标,将布局中的重力设置为“center_vertical|start”或“center_vertical|end”非常重要。例如:

                          <com.stackoverflow.util.IconButton
                                  android:id="@+id/cancel_btn"
                                  android:layout_width="0dp"
                                  android:layout_height="wrap_content"
                                  android:layout_weight="1"
                                  android:drawableStart="@drawable/cancel"
                                  android:drawablePadding="@dimen/padding_small"
                                  android:gravity="center_vertical|start"
                                  android:text="Cancel" />
                          

                          这个实现的唯一问题是按钮只能有单行文本,否则文本区域会填充按钮并且填充将为0。

                          【讨论】:

                            【解决方案27】:

                            试试这个你会找到你要找的,

                             <Button
                               android:id="@+id/button_my_profile"
                               style="@style/whiteTextBlackButtonStyle.size18"
                               android:layout_width="0dp"
                               android:layout_weight="1"
                               android:layout_height="wrap_content"
                               android:gravity="center"
                               android:drawableTop="@drawable/ic_more_profile"
                               android:drawablePadding="8dp"
                               android:paddingStart="16dp"
                               android:text="@string/title_my_profile"
                               android:textAllCaps="false"
                               tools:layout_editor_absoluteY="24dp" />
                            

                            【讨论】:

                              【解决方案28】:

                              考虑ImageButton

                              android:src 属性可用于设置在 Button 中居中的可绘制对象。

                              <ImageButton
                                  android:src="@drawable/your_drawable"
                                  ...
                              />
                              

                              【讨论】:

                                【解决方案29】:

                                使用这个 android:background="@drawable/ic_play_arrow_black_24dp"

                                只需将背景设置为要居中的图标

                                【讨论】:

                                  猜你喜欢
                                  • 2012-07-26
                                  • 2017-03-19
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 1970-01-01
                                  • 2013-09-06
                                  • 1970-01-01
                                  • 2015-08-29
                                  • 2016-02-08
                                  相关资源
                                  最近更新 更多