【问题标题】:Aligning drawableLeft with text of button将 drawableLeft 与按钮的文本对齐
【发布时间】:2013-01-18 01:25:25
【问题描述】:

这是我的布局:

我面临的问题是可绘制复选标记。我将如何将它与文本对齐,它们都在按钮内居中?这是 XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".PostAssignmentActivity" >

    <LinearLayout
        style="?android:attr/buttonBarStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal" >

        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:drawableLeft="@drawable/ic_checkmark_holo_light"
            android:text="Post" />

        <Button
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="Cancel" />
    </LinearLayout>

</RelativeLayout>

应用 android:gravity="center_vertical" 将文本和 drawable 拉到一起,但随后文本不再居中对齐。

【问题讨论】:

    标签: android android-layout


    【解决方案1】:

    解决方案 1

    在您的第一个按钮中设置android:paddingLeft。这将强制drawableLeftpaddingLeft 数量向右。这是快速/hacky 的解决方案。

    解决方案 2

    不要使用 ButtonView,而是使用包含 textview 和 imageview 的 LinearLayout。这是一个更好的解决方案。它使您可以更灵活地定位复选标记。

    将您的 ButtonView 替换为以下代码。您需要LinearLayoutTextView 才能使用buttonBarButtonStyle,以便选择时背景颜色正确且文本大小正确。您需要为孩子设置android:background="#0000",以便只有 LinearLayout 处理背景颜色。

    <LinearLayout
        style="?android:attr/buttonBarButtonStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="horizontal" >
        <ImageView 
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:clickable="false"
            android:background="#0000"
            android:src="@drawable/ic_checkmark_holo_light"/>
        <TextView
            style="?android:attr/buttonBarButtonStyle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:clickable="false"
            android:background="#0000"
            android:text="Done" />
    </LinearLayout>
    

    这是我在尝试时截取的一些屏幕截图。

    【讨论】:

    • 由于 ListViews 内部的性能原因,使用嵌套的 LinearLayouts 具有深层视图层次结构是一个坏主意。我不认为这应该是一个问题。
    • 感谢您撰写如此详细的文章! :)
    • 出于性能和代码可读性的原因,这是一个糟糕的解决方案。使用 paddings 是一种更好的解决方案,如果还不够,您可以考虑使用 Canvas 和 onDraw() 方法扩展 Button 视图和绘图图标。
    • Pawla,你重申了一个好观点。如果您的布局包含很多按钮(可能在 ListView 中),我的解决方案 #1 无法处理您的设计并且您遇到性能问题:您可能希望覆盖 Button 以最小化层次结构中的视图数量。但要小心在 RTL 布局中进行测试。
    • 你是不是忘记在LinearLayout中设置要集中的重力?
    【解决方案2】:

    这些解决方案都不能正常工作,除非做出不可接受的权衡(创建一个包含视图的布局?这不是一个好主意)。那么为什么不自己动手呢?这是我得到的:

    首先用这个创建一个attrs.xml

    <resources>
        <declare-styleable name="IconButton">
            <attr name="iconSrc" format="reference" />
            <attr name="iconSize" format="dimension" />
            <attr name="iconPadding" format="dimension" />
        </declare-styleable>
    </resources>
    

    这允许在我们的新视图中创建具有特定大小、文本填充和图像的图标。视图代码如下所示:

    public class IconButton extends Button {
        private Bitmap mIcon;
        private Paint mPaint;
        private Rect mSrcRect;
        private int mIconPadding;
        private int mIconSize;
    
        public IconButton(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(context, attrs);
        }
    
        public IconButton(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context, attrs);
        }
    
        public IconButton(Context context) {
            super(context);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            int shift = (mIconSize + mIconPadding) / 2;
    
            canvas.save();
            canvas.translate(shift, 0);
    
            super.onDraw(canvas);
    
            if (mIcon != null) {
                float textWidth = getPaint().measureText((String)getText());
                int left = (int)((getWidth() / 2f) - (textWidth / 2f) - mIconSize - mIconPadding);
                int top = getHeight()/2 - mIconSize/2;
    
                Rect destRect = new Rect(left, top, left + mIconSize, top + mIconSize);
                canvas.drawBitmap(mIcon, mSrcRect, destRect, mPaint);
            }
    
            canvas.restore();
        }
    
        private void init(Context context, AttributeSet attrs) {
            TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.IconButton);
    
            for (int i = 0; i < array.getIndexCount(); ++i) {
                int attr = array.getIndex(i);
                switch (attr) {
                    case R.styleable.IconButton_iconSrc:
                        mIcon = drawableToBitmap(array.getDrawable(attr));
                        break;
                    case R.styleable.IconButton_iconPadding:
                        mIconPadding = array.getDimensionPixelSize(attr, 0);
                        break;
                    case R.styleable.IconButton_iconSize:
                        mIconSize = array.getDimensionPixelSize(attr, 0);
                        break;
                    default:
                        break;
                }
            }
    
            array.recycle();
    
            //If we didn't supply an icon in the XML
            if(mIcon != null){
                mPaint = new Paint();
                mSrcRect = new Rect(0, 0, mIcon.getWidth(), mIcon.getHeight());
            }
        }
    
        public static Bitmap drawableToBitmap (Drawable drawable) {
            if (drawable instanceof BitmapDrawable) {
                return ((BitmapDrawable)drawable).getBitmap();
            }
    
            Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
            drawable.draw(canvas);
    
            return bitmap;
        }
    }
    

    然后就可以这样使用了:

    <com.example.grennis.myapplication.IconButton
        android:layout_width="200dp"
        android:layout_height="64dp"
        android:text="Delete"
        app:iconSrc="@android:drawable/ic_delete"
        app:iconSize="32dp"
        app:iconPadding="6dp" />
    

    这对我有用。

    【讨论】:

    • 小心在 Android 5 lollipop 上使用 measureText() 它将绘制按钮文本全部大写,但 measureText() 将返回在 xml 中定义的字符串。使用明确的全部大写来解决这个问题。
    • 这对我来说是最好的解决方案,因为我不必重现材料设计按钮默认具有的漂亮效果
    • 很好的解决方案,除了 imo 有一个错误。图像和文本未居中。要居中,您需要移动 canvas.restore();就在 super.onDraw(canvas); 后面
    • 如何处理将宽度设置为 match_parent 或 wrap_content 的按钮?我假设您必须覆盖 onMeasure
    • @GregEnnis Use explicit all caps to fix this 是什么意思?可以举个例子吗?
    【解决方案3】:

    这是一个干净简单的方法,无需做任何花哨的操作,即可获得比居中的 Image 和 Text 内容更宽的 Button 的结果。

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:clickable="true"
        android:background="@drawable/button_background_selector">
    
        <Button
            android:layout_centerInParent="true"
            android:gravity="center"
            android:duplicateParentState="true"
            android:layout_width="wrap_content"
            android:text="New User"
            android:textSize="15sp"
            android:id="@android:id/button1"
            android:textColor="@android:color/white"
            android:drawablePadding="6dp"
            android:drawableLeft="@drawable/add_round_border_32x32"
            android:layout_height="64dp" />
    
    </RelativeLayout>
    

    【讨论】:

    • 这是创建此类按钮的最简单解决方案。
    • 使用RelativeLayout的方式很糟糕,不要这样做。
    • 在 RelativeLayout 中嵌套标准复选框对我来说非常有用。按钮图像向左倾斜,文本的距离可变,具体取决于父级/屏幕大小的大小......嵌套在 RelativeLayout 中标准化了复选框的大小(按钮和文本看起来很好)并允许两者居中。
    • 这样做的缺点是很多看起来像按钮的东西是不可点击的。如果您的按钮在按下/等时发生状态更改,它看起来会很奇怪。
    • 对我来说,这是迄今为止最有用的部分:" android:drawablePadding="6dp" 谢谢。
    【解决方案4】:

    你可以使用 &lt;com.google.android.material.button.MaterialButton/&gt; .
    https://material.io/develop/android/components/material-button/

    终于可以设置图标的重力了。

     <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" />
    

    【讨论】:

    • 这是比其他更好的解决方案
    【解决方案5】:

    在我们的例子中,我们想要使用默认的 Button 类(继承其各种样式和行为),并且我们需要能够在代码中创建按钮。此外,在我们的例子中,我们可以有文本、图标(左可绘制),或两者兼有。

    目标是当按钮宽度大于 wrap_content 时,将图标和/或文本作为一个组居中。

    public class CenteredButton extends Button
    {
        public CenteredButton(Context context, AttributeSet attrs, int defStyleAttr)
        {
            super(context, attrs, defStyleAttr);
    
            // We always want our icon and/or text grouped and centered.  We have to left align the text to
            // the (possible) left drawable in order to then be able to center them in our onDraw() below.
            //
            setGravity(Gravity.LEFT|Gravity.CENTER_VERTICAL);
        }
    
        @Override
        protected void onDraw(Canvas canvas)
        {
            // We want the icon and/or text grouped together and centered as a group.
    
            // We need to accommodate any existing padding
            //
            float buttonContentWidth = getWidth() - getPaddingLeft() - getPaddingRight();
    
            // In later versions of Android, an "all caps" transform is applied to buttons.  We need to get
            // the transformed text in order to measure it.
            //
            TransformationMethod method = getTransformationMethod();
            String buttonText = ((method != null) ? method.getTransformation(getText(), this) : getText()).toString();
            float textWidth = getPaint().measureText(buttonText);
    
            // Compute left drawable width, if any
            //
            Drawable[] drawables = getCompoundDrawables();
            Drawable drawableLeft = drawables[0];
            int drawableWidth = (drawableLeft != null) ? drawableLeft.getIntrinsicWidth() : 0;
    
            // We only count the drawable padding if there is both an icon and text
            //
            int drawablePadding = ((textWidth > 0) && (drawableLeft != null)) ? getCompoundDrawablePadding() : 0;
    
            // Adjust contents to center
            //
            float bodyWidth = textWidth + drawableWidth + drawablePadding;
            canvas.translate((buttonContentWidth - bodyWidth) / 2, 0);
    
            super.onDraw(canvas);
        }
    }
    

    【讨论】:

    • 我喜欢这个解决方案,因为它正确地呈现了我的可绘制色调。但是,我希望文本以左侧图标为中心,而此代码以图标+文本为中心。我用 Greg 的 IconButton 示例中的值替换了 translate 以便它可以工作: int left = (int)((getWidth() / 2f) - (textWidth / 2f) - drawableWidth - drawablePadding); canvas.translate(left, 0);
    • 感谢您的代码。为了让 Tint 使用 compat 库,我扩展了 AppCompatButton 而不是常规 Button
    • 这是迄今为止 IMO 最好的解决方案!只需要一个类,代码很少,并且还使用现有的 android 属性来实现复合绘图。
    • 我想补充一点,为了使这项工作始终如一,您必须在按钮中设置重力,如下所示:android:gravity="left|center_vertical"。这是因为重力默认为按钮的“中心”,并且这个类也使按钮的内容居中,导致了意想不到的结果。
    【解决方案6】:

    这是我的代码,工作完美。

    <Button
        android:id="@+id/button"
        android:layout_width="200dp"
        android:layout_height="50dp"
        android:layout_gravity="center"
        android:background="@drawable/green_btn_selector"
        android:gravity="left|center_vertical"
        android:paddingLeft="50dp"
        android:drawableLeft="@drawable/plus"
        android:drawablePadding="5dp"
        android:text="@string/create_iou"
        android:textColor="@color/white" />
    

    【讨论】:

    • 出于可访问性原因,按钮也更好。使用辅助功能的用户不知道他们应该按下带有 ImageView 和 TextView 的 LinearLayout。
    • +1 for android:drawablePadding 完美运行 @CliveJefferies 它适用于尺寸 wrap content
    【解决方案7】:
    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);
        }
    }
    

    【讨论】:

      【解决方案8】:

      现在,Material Button 默认使用 app:iconGravity 属性提供此功能。但是,Material Button 不允许将背景设置为可绘制(RIP 渐变)。

      我将上面@BobDickinson@David-Medenjak 的答案转换为kotlin,效果很好。

      import android.content.Context
      import android.graphics.Canvas
      import android.util.AttributeSet
      import android.view.Gravity
      import androidx.appcompat.widget.AppCompatButton
      import kotlin.math.max
      
      class CenteredButton @JvmOverloads constructor(
        context: Context,
        attrs: AttributeSet? = null,
        defStyle: Int = R.attr.buttonStyle
      ) : AppCompatButton(context, attrs, defStyle) {
      
        init {
          gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
        }
      
        override fun onDraw(canvas: Canvas) {
          val buttonContentWidth = (width - paddingLeft - paddingRight).toFloat()
      
          var textWidth = 0f
          layout?.let {
            for (i in 0 until layout.lineCount) {
              textWidth = max(textWidth, layout.getLineRight(i))
            }
          }
      
          val drawableLeft = compoundDrawables[0]
          val drawableWidth = drawableLeft?.intrinsicWidth ?: 0
          val drawablePadding = if (textWidth > 0 && drawableLeft != null) compoundDrawablePadding else 0
      
          val bodyWidth = textWidth + drawableWidth.toFloat() + drawablePadding.toFloat()
      
          canvas.save()
          canvas.translate((buttonContentWidth - bodyWidth) / 2, 0f)
          super.onDraw(canvas)
          canvas.restore()
        }
      }
      

      【讨论】:

        【解决方案9】:

        我知道这有点晚了,但是如果有人在寻找另一个答案,这是另一种添加图标的方法,而无需使用 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>
        

        *需要将 textAllCaps 设置为 false 才能使 spannable 正常工作


        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
            }
        }
        

        【讨论】:

          【解决方案10】:

          我从@BobDickinson's answer 开始,但它不能很好地处理多行。这种方法很好,因为您最终仍然会得到一个可以正确重复使用的Button

          这是一个经过调整的解决方案,如果按钮有多行也可以工作(请不要问为什么。)

          只需扩展Button并在onDraw中使用以下内容,getLineRight()用于查找每行的实际长度。

          @Override
          protected void onDraw(Canvas canvas) {
              // We want the icon and/or text grouped together and centered as a group.
              // We need to accommodate any existing padding
              final float buttonContentWidth = getWidth() - getPaddingLeft() - getPaddingRight();
          
              float textWidth = 0f;
              final Layout layout = getLayout();
              if (layout != null) {
                  for (int i = 0; i < layout.getLineCount(); i++) {
                      textWidth = Math.max(textWidth, layout.getLineRight(i));
                  }
              }
          
              // Compute left drawable width, if any
              Drawable[] drawables = getCompoundDrawables();
              Drawable drawableLeft = drawables[0];
              int drawableWidth = (drawableLeft != null) ? drawableLeft.getIntrinsicWidth() : 0;
          
              // We only count the drawable padding if there is both an icon and text
              int drawablePadding = ((textWidth > 0) && (drawableLeft != null)) ? getCompoundDrawablePadding() : 0;
          
              // Adjust contents to center
              float bodyWidth = textWidth + drawableWidth + drawablePadding;
          
              canvas.save();
              canvas.translate((buttonContentWidth - bodyWidth) / 2, 0);
              super.onDraw(canvas);
              canvas.restore();
          }
          

          【讨论】:

            【解决方案11】:

            这是另一种解决方案:

                 <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>
            

            和事件:

                LinearLayout btnCall = (LinearLayout) findViewById(R.id.llButton);
                btnCall.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        call(runid.Phone);
                    }
                });
            

            【讨论】:

              【解决方案12】:

              我遇到了同样的问题,我想出了一个不需要更改 XML 或自定义视图的解决方案。

              这段代码 sn-p 检索文本的宽度和左/右可绘制对象,并设置按钮的左/右填充,因此只有足够的空间来绘制文本和可绘制对象,并且不会再有填充添加。 这可以应用于 Buttons 以及 TextViews,它们的超类。

              public class TextViewUtils {
                  private static final int[] LEFT_RIGHT_DRAWABLES = new int[]{0, 2};
              
                  public static void setPaddingForCompoundDrawableNextToText(final TextView textView) {
                      ViewTreeObserver vto = textView.getViewTreeObserver();
                      vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                          @Override
                          public void onGlobalLayout() {
                              shinkRoomForHorizontalSpace(textView);
                          }
                      });
              
                  }
              
                  private static void shinkRoomForHorizontalSpace(TextView textView) {
                      int textWidth = getTextWidth(textView);
                      int sideCompoundDrawablesWidth = getSideCompoundDrawablesWidth(textView);
                      int contentWidth = textWidth + sideCompoundDrawablesWidth;
                      int innerWidth = getInnerWidth(textView);
                      int totalPadding = innerWidth - contentWidth;
                      textView.setPadding(totalPadding / 2, 0, totalPadding / 2, 0);
                  }
              
                  private static int getTextWidth(TextView textView) {
                      String text = textView.getText().toString();
                      Paint textPaint = textView.getPaint();
                      Rect bounds = new Rect();
                      textPaint.getTextBounds(text, 0, text.length(), bounds);
                      return bounds.width();
                  }
              
                  private static int getSideCompoundDrawablesWidth(TextView textView) {
                      int sideCompoundDrawablesWidth = 0;
                      Drawable[] drawables = textView.getCompoundDrawables();
                      for (int drawableIndex : LEFT_RIGHT_DRAWABLES) {
                          Drawable drawable = drawables[drawableIndex];
                          if (drawable == null)
                              continue;
                          int width = drawable.getBounds().width();
                          sideCompoundDrawablesWidth += width;
                      }
                      return sideCompoundDrawablesWidth;
                  }
              
                  private static int getInnerWidth(TextView textView) {
                      Rect backgroundPadding = new Rect();
                      textView.getBackground().getPadding(backgroundPadding);
                      return textView.getWidth() - backgroundPadding.left - backgroundPadding.right;
                  }
              }
              

              注意:

              • 它实际上仍然留下了比需要更多的空间(对于我的目的来说已经足够了,但您可能会寻找错误)
              • 它会覆盖那里的任何左/右填充。我想解决这个问题并不难。

              要使用它,只需在您的onCreateonViewCreated() 上致电TextViewUtils.setPaddingForCompoundDrawableNextToText(button)

              【讨论】:

              • 很久没有尝试过这样的事情了,但是在 2.x、4.x、5.x 和 6.x API 的时代,每个 API 对文本像素大小的评估都不同,我从来没有设法在所有想要的 Android 版本中获得通用的工作代码,尤其是 5.x 和 6.x 是完全不同的 IIRC,包括实现这些功能的一些内部错误......如果你对常见的 API 进行了一些广泛的测试今天,在你的回答中说明你知道它运作良好会很有帮助。
              【解决方案13】:

              这个问题有几种解决方案。也许在某些设备上最简单的方法是使用paddingRightpaddingLeft 将图像和文本移动到彼此旁边,如下所示。

              原始按钮

              <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"
                  />
              

              这里的问题是在较小的设备上,这种填充可能会导致不幸的问题,例如:

              其他解决方案都是“从布局、图像和文本视图构建按钮”的某个版本。它们可以工作,但完全模拟一个按钮可能会很棘手。我提出了另一种解决方案; "从布局中构建一个按钮,一个图像、一个文本视图、和一个按钮"

              这是我建议的相同按钮:

              <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>
              

              如您所见,按钮现在处于相对布局中,但它的文本和 drawableLeft 不是按钮的一部分,它们位于按钮顶部的单独布局中。有了这个,按钮仍然像一个按钮。问题是:

              1. 对于较新版本的 Android,内部布局需要提升。按钮本身的海拔高于 ImageView 和 TextView,因此即使它们是在 Button 之后定义的,它们仍然会在海拔“下方”并且不可见。将 'android:elevation' 设置为 10 即可解决此问题。
              2. 必须设置 TextView 的 textAppearance,使其具有与按钮相同的外观。

              【讨论】:

                【解决方案14】:

                另一个相当老套的选择是在按钮的每一侧添加带有weight="1" 的空白间隔视图。我不知道这会如何影响性能。

                    <View
                        android:layout_width="0dp"
                        android:layout_height="fill_parent"
                        android:layout_weight="1" />
                

                【讨论】:

                • 我不认为这是可能的,你不能在按钮内添加元素
                • 您可以将间隔视图放在按钮的任一侧而不是按钮内。它将按钮的文本和可绘制对象居中。间隔区域不是按钮的可点击部分。这种技术也可以用于使包含布局可点击。这不是一个很好的解决方案,但它可能适合某些人。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-01-15
                • 2021-08-25
                • 2016-08-25
                • 2017-10-01
                • 2020-02-26
                • 1970-01-01
                相关资源
                最近更新 更多