如何正确删除 Android 中按钮周围的填充(或边距?)?

How to properly remove padding (or margin?) around buttons in Android?

目前,我有以下底部登录按钮。

未按下按钮时

按下按钮时

XML 看起来像这样

<LinearLayout
    android:background="?attr/welcomeBottomNavBarBackground"
    android:orientation="horizontal"
    android:id="@+id/sign_in_bottom_nav_bar"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true">
    <Button
        style="?android:attr/buttonBarButtonStyle"
        android:id="@+id/sign_in_button"
        android:layout_width="0dp"
        android:width="0dp"
        android:layout_weight="1.0"
        android:layout_height="48dp"
        android:gravity="center"
        android:layout_gravity="center"
        android:enabled="true"
        android:textAllCaps="true"
        android:text="@string/log_in" />
</LinearLayout>

我想在按下按钮时移除按钮周围的填充(或者我应该称之为边距吗?请参阅我最底部的 p/s 部分)。

我看看How to remove padding around buttons in Android?

我试过了

<Button
    ...
    ...
    android:minHeight="0dp"
    android:minWidth="0dp" />

不起作用,没有效果。


我再试试

<Button
    ...
    ...
    android:background="@null"
    android:minHeight="0dp"
    android:minWidth="0dp" />

按下时不再填充。但是,material设计的按压视觉效果也会消失。

我可以知道在按下时移除按钮填充的最佳方法是什么,同时保留 material 设计的按下视觉效果吗?

P/S

我真的不知道我应该称它为填充还是边距。我希望实现的是,当我们按下底部区域时,按下视觉效果变化应该覆盖整个 100% 底部栏区域 (@+id/sign_in_bottom_nav_bar),而不是当前的 95% 底部栏区域。

我认为最好的解决方案是创建您自己的 Ripple Effect。按下按钮时的填充符合组件的默认 Ripple Effect

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?attr/colorControlHighlight">
    <item android:drawable="?attr/colorPrimary"/>
</ripple>

或者您可以尝试将按钮的样式更改为 style="?android:textAppearanceSmall"

记住:此效果仅在 Android Lollipop (API 21) 或更高版本上显示。

styles.xml

<style name="MyButtonStyle" parent="Base.Widget.AppCompat.Button">
    <item name="android:background">@drawable/selector</item>
    <item name="android:textColor">@android:color/black</item>
</style>

values/drawable中:

my_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="2dp" />
    <!-- specify your desired color here -->
    <solid android:color="#9e9b99" />
</shape>

selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_focused="true" android:drawable="@drawable/my_drawable"/>
    <item android:state_pressed="true" android:drawable="@drawable/my_drawable"/>
    <item android:drawable="@android:color/transparent"/>
</selector>

values/drawable-v21中:

my_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle"
       android:tint="?attr/colorButtonNormal"
       xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="2dp" />
    <solid android:color="@android:color/white" />
</shape>

selector.xml

<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?attr/colorControlHighlight">
    <item android:id="@android:id/mask"
          android:drawable="@drawable/my_drawable" />
</ripple>

布局中:

<Button
    android:id="@+id/button"
    style="@style/MyButtonStyle"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:text="Test"/>

API19 的结果:

API21 的结果:

Source code

标准按钮不应在全宽下使用,这就是您遇到此问题的原因。

背景

如果你看一下 Material Design - Button Style 你会看到一个按钮有一个 48dp 高度的点击区域,但会显示为 36dp 的高度...出于某种原因。

这是您看到的背景轮廓,不会覆盖按钮本身的整个区域。
它有圆角和一些填充,应该可以自行点击,包裹其内容,并且不会跨越屏幕底部的整个宽度。

解决方案

如上所述,你想要的是不同的背景。不是标准按钮,而是具有这种漂亮波纹效果的可选项目的背景。

对于此用例,有 ?selectableItemBackground 主题属性,您可以将其用于背景(尤其是在列表中)。
它将添加一个平台标准波纹(或 < 21 上的一些颜色状态列表)并将使用您当前的主题颜色。

对于您的用例,您可能只使用以下内容:

<Button
    android:id="@+id/sign_in_button"
    style="?android:attr/buttonBarButtonStyle"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:text="Login"
    android:background="?attr/selectableItemBackground" />
                   <!--  /\ that's all -->

如果您的视图是唯一的且横跨整个屏幕,则也无需添加布局权重

如果您对背景应该是什么样子有一些不同的想法,您必须自己创建一个自定义可绘制对象,并在那里管理颜色和状态。

我建议你先看看 this 以防万一。

然后,如果不起作用,我建议您使用 android xml 可绘制对象和可绘制状态来区分 pressed/notpressed。

我认为使用您自己的样式可能是最好的答案,因为它可以让您更好地控制应用的显示方式,但使用 android 默认主题和样式还允许用户拥有自定义样式这是个好主意。但是,您无法测试每个自定义样式,因此您无法检查您的应用程序是否会在所有自定义样式上正确显示,因此可能会遇到一些问题。

设置 Button 背景为 android:background="?selectableItemBackground"

<LinearLayout
    android:background="?attr/welcomeBottomNavBarBackground"
    android:orientation="horizontal"
    android:id="@+id/sign_in_bottom_nav_bar"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true">

    <Button
        style="?android:attr/buttonBarButtonStyle"
        android:background="?selectableItemBackground"
        android:id="@+id/sign_in_button"
        android:layout_width="0dp"
        android:width="0dp"
        android:layout_weight="1.0"
        android:layout_height="48dp"
        android:gravity="center"
        android:layout_gravity="center"
        android:enabled="true"
        android:textAllCaps="true"
        android:text="@string/log_in" />

</LinearLayout>

1.add 一个名为 button_background.xml

的可绘制资源文件
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true">
        <shape>
            <solid android:color="#ff0000"/>
            <stroke android:width="5dp" android:color="#00ff00"/>
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="#00ff00"/>
        </shape>
    </item>
</selector>

2.Use button_background.xml 作为按钮背景,大功告成!

github

blog

I don't really know whether I should call it padding or margin.

该按钮正在执行表面高度,以提供响应触摸的视觉反馈。它是用于 surface reaction; the first one being the ripple effect. For example, a raised button has resting state elevation of 2dp and pressed state elevation of 8dp (See raised button under Shadows) 的两个反馈之一。当手指接触表面时,按钮会遇到手指。

May I know what is the best way to remove button padding during pressed, yet retain the material designed pressed visual effect?

回答完第一部分后,如果您想消除表面高程效果,我不相信您拥有所有 material 设计。

无论如何,这里是如何删除表面高度视觉反馈:

将动画文件button_raise.xml添加到res目录下的animator目录,代码如下:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:state_enabled="true"
        android:state_pressed="true">

        <objectAnimator
            android:duration="@android:integer/config_shortAnimTime"
            android:propertyName="translationZ"
            android:valueTo="0dp"
            android:valueType="floatType" />
    </item>
</selector>

使用stateListAnimator 属性:

在按钮中引用新创建的动画师
<Button
    ...
    android:stateListAnimator="@animator/button_raise"
    ... />

希望对您有所帮助。

我经历过你正在经历的事情。长话短说,你不能单独使用 <Button> 标签来干净地完成它,同时确保向后兼容性。

最简单和最广泛使用的方法是在 <Button>.

周围使用 <RelativeLayout> 底层

按钮代码:

        <RelativeLayout
            android:id="@+id/myButtonUnderlay"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:visibility="visible">

            <Button
                android:id="@+id/myButton"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:background="?attr/selectableItemBackgroundBorderless"
                android:text="I am as cute as a Button"/>

        </RelativeLayout>

无论在何处需要使用按钮,都可以使用此完整代码。

细分如下:


  1. OnClick 事件将挂接到 myButton
  2. 通过更改 myButtonUnderlay 的属性来控制按钮的尺寸。
  3. myButtonandroid:background="?attr/selectableItemBackgroundBorderless"。这将使它成为一个只有文本的透明按钮,并向后兼容波纹。
  4. myButtonUnderlay 中,您将完成所有其他后台应用程序,例如设置按钮的颜色、边距、填充、边框、渐变和阴影等。
  5. 如果希望操纵按钮的可见性(程序化或非程序化),您可以在 myButtonUnderlay 上进行。

注意:为确保向后兼容性,请确保使用

android:background="?attr/selectableItemBackgroundBorderless",并且 不是

android:background="?android:attr/selectableItemBackgroundBorderless"

作为@David Medenjak 的回答,您可以在其开发者网站上阅读 Google Material 设计 Button-style。正如@David Medenjak 在他的回答中解释的那样使用按钮样式。您也可以通过以下方式进行 它不是填充或边距,但它实际上是按钮的背景效果。 如果你想删除它,那么你可以执行以下操作。

Option 1:

第 1 步:将以下代码放入 styles.xml

<style name="myColoredButton">
        <item name="android:textColor">#FF3E96</item>
        <item name="android:padding">0dp</item>
        <item name="android:minWidth">88dp</item>
        <item name="android:minHeight">36dp</item>
        <item name="android:elevation">1dp</item>
        <item name="android:translationZ">1dp</item>
        <item name="android:background">#FF0000</item>
    </style>

步骤 2:Create 在 drawables 文件夹下创建一个新的 XML 文件并添加以下代码:我将我的 XML 文件命名为 button_prime.xml

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/colorPrimary">
    <item>
        <shape xmlns:android="http://schemas.android.com/apk/res/android">
            <corners android:radius="1dp" />
            <solid android:color="#8B8386" />
        </shape>
    </item>
</ripple>

第 3 步:按如下方式在 Button 中使用样式和可绘制对象。

<Button
        style="@style/myColoredButton"
        android:layout_width="250dp"
        android:layout_height="50dp"
        android:text="Cancel"
        android:gravity="center"
        android:background="@drawable/button_prime"
        android:colorButtonNormal="#3578A9" />

Option 2:

使用支持库 v7,所有样式实际上都已经定义好并可以使用了,对于标准按钮,所有这些样式都是available.So你可以像这样设置你的按钮样式

<Button
    style="@style/Widget.AppCompat.Button.Borderless"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:text="BUTTON"
    android:gravity="center"
    android:minHeight="0dp"
    android:minWidth="0dp"
    android:background="@color/colorAccent"/>

有关按钮样式的更多详细信息,请check 此答案

我想你也会检查一下 。我希望你能得到你的解决方案。

填充和边距可能是按钮中使用的原始资源的结果。

因此您可以尝试使用选择器更改使用的资源:

<selector
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@drawable/btn_action_hover" />
    <item android:state_selected="true" android:drawable="@drawable/btn_action_hover" />
    <item android:state_focused="true" android:drawable="@drawable/btn_action_hover" />
    <item android:drawable="@drawable/btn_action_normal" />
</selector>

这会更改按钮的默认设置 images/shapes,因此您可以尝试使用可绘制对象并将每个项目设置为可绘制对象。可绘制对象可以是位图,也可以是 .xml 文件(样式文件),用于定义按钮在其当前状态下的外观。我假设即使您自己设置了按钮样式,仍然包含一些原生样式。这可能是因为您没有使用自定义主题。所以这个问题也可以通过 defing

来解决
theme="@style/myNewTheme"

其中 myNewTheme 是您的主题,它应该有任何父主题(parent="" 不应被定义)。

采用任何给定的主题(由 Google/Android 设计,例如 Theme.AppCompat.[name]),它也带有 buttonStyle。这是 Theme.Holo.Light 的一部分:

    <!-- Button styles -->
    <item name="buttonStyle">@style/Widget.Holo.Light.Button</item>

    <item name="buttonStyleSmall">@style/Widget.Holo.Light.Button.Small</item>
    <item name="buttonStyleInset">@style/Widget.Holo.Light.Button.Inset</item>

    <item name="buttonStyleToggle">@style/Widget.Holo.Light.Button.Toggle</item>
    <item name="switchStyle">@style/Widget.Holo.Light.CompoundButton.Switch</item>
    <item name="mediaRouteButtonStyle">@style/Widget.Holo.Light.MediaRouteButton</item>

    <item name="selectableItemBackground">@drawable/item_background_holo_light</item>
    <item name="selectableItemBackgroundBorderless">?attr/selectableItemBackground</item>
    <item name="borderlessButtonStyle">@style/Widget.Holo.Light.Button.Borderless</item>
    <item name="homeAsUpIndicator">@drawable/ic_ab_back_holo_light</item>

如您所见,此主题定义了您的按钮 look/work 的基本功能。您可以覆盖它的一部分,但您还没有覆盖重要的部分(即 buttonStyle 和类似的部分)。因此,如果您自己创建一个新主题并根据自己的喜好设置样式并设置主题(使用 theme="themename")并且该主题不继承任何主题,您应该能够根据自己的喜好设置按钮样式而无需担心主题中的默认样式

基本上:

调用 padding/margin="0dp" 无济于事。主题定义的默认可绘制对象在按钮可绘制对象中有这个,这意味着您无法更改它。所以你要么改变按钮样式,要么完全改变主题。确保该主题没有任何父主题,因为许多主题定义了按钮样式。您不想要主题定义的按钮样式。

在尝试了很多解决方案之后,最后我得出的结论是,仅靠标签是无法实现这一点的。要删除这个不需要的 space 按钮,我的解决方案如下:

 <RelativeLayout
    android:id="@+id/myButtonUnderlay"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:visibility="visible">
<Button
    android:id="@+id/save_button"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_marginTop="-5dp" 
    android:layout_marginBottom="-5dp"
    android:layout_above="@+id/content_scrollview"
    android:layout_gravity="bottom"
    android:background="@drawable/ripple_theme"
    android:enabled="true"
    android:text="SetUp Store"
    android:textColor="#fff"
    android:textSize="18sp"
    android:visibility="gone"
    tools:visibility="visible"
    style="@style/MediumFontTextView" />
</RelativeLayout>

很简单,使用 inset 属性 如:

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

目前最好的解决方案就是使用 MaterialButton 代替 Button

Note: MaterialButton is visually different from Button and AppCompatButton. One of the main differences is that AppCompatButton has a 4dp inset on the left and right sides, whereas MaterialButton does not. To add an inset to match AppCompatButton, set android:insetLeft and android:insetRight on the button to 4dp, or change the spacing on the button’s parent layout.

When replacing buttons in your app with MaterialButton, you should inspect these changes for sizing and spacing differences.

来源:https://material.io/develop/android/components/material-button/