111

我正在使用 Google 设计库中的新 FloatingActionButton,但遇到了一些奇怪的填充/边距问题。此图像(打开开发人员布局选项)来自 API 22。

在此处输入图像描述

从 API 17 开始。

在此处输入图像描述

这是 XML

<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentEnd="true"
        android:layout_gravity="bottom|right"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="20dp"
        android:layout_marginTop="-32dp"
        android:src="@drawable/ic_action_add"
        app:fabSize="normal"
        app:elevation="4dp"
        app:borderWidth="0dp"
        android:layout_below="@+id/header"/>

为什么 API 17 中的 FAB 有这么大的填充/边距?

4

7 回答 7

131

更新(2016 年 10 月):

现在正确的解决方案是放入app:useCompatPadding="true"您的 FloatingActionButton。这将使不同 API 版本之间的填充保持一致。但是,这似乎仍然会使默认边距减少一点,因此您可能需要调整这些边距。但至少不再需要特定于 API 的样式。

上一个答案:

您可以使用特定于 API 的样式轻松完成此操作。在您的 normalvalues/styles.xml中,放置如下内容:

<style name="floating_action_button">
    <item name="android:layout_marginLeft">0dp</item>
    <item name="android:layout_marginTop">0dp</item>
    <item name="android:layout_marginRight">8dp</item>
    <item name="android:layout_marginBottom">0dp</item>
</style>

然后在 values-v21/styles.xml 下,使用这个:

<style name="floating_action_button">
    <item name="android:layout_margin">16dp</item>
</style>

并将样式应用于您的 FloatingActionButton:

<android.support.design.widget.FloatingActionButton
...
style="@style/floating_action_button"
...
/>

正如其他人所指出的,在 API <20 中,按钮呈现自己的阴影,这增加了视图的整体逻辑宽度,而在 API >=20 中,它使用了新的 Elevation 参数,这些参数对视图宽度没有影响。

于 2015-06-16T22:29:44.130 回答
51

不再摆弄文件styles.xml.java文件。让我简单点。

您可以使用和删除自定义边距以在不同版本的 android 之间app:useCompatPadding="true"保持相同的边距

您在第二张图片的 FAB 上看到的额外边距/填充是由于棒棒糖前设备上的这种compatPadding造成的。如果未设置此属性,它将应用于棒棒糖之前的设备,而不是棒棒糖+设备。

安卓工作室代码

概念证明

设计视图

于 2016-04-24T12:16:16.273 回答
32

经过几次搜索和测试解决方案后,我解决了我的问题,仅将此行添加到我的 xml 布局中:

app:elevation="0dp"
app:pressedTranslationZ="0dp"

这是我的整个浮动按钮布局

<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginRight="16dp"
        android:layout_marginBottom="16dp"
        android:src="@drawable/ic_add"
        app:elevation="0dp"
        app:pressedTranslationZ="0dp"
        app:fabSize="normal" />
于 2016-06-02T13:49:38.773 回答
22

设计支持库中存在问题。在更新库之前,请使用以下方法解决此问题。尝试将此代码添加到您的活动或片段中以解决问题。保持您的 xml 相同。在棒棒糖和上面没有边距,但在下面有 16dp 的边距。

更新工作示例

XML - FAB 在相对布局内

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_marginBottom="16dp"
    android:layout_marginRight="16dp"
    android:src="@mipmap/ic_add"
    app:backgroundTint="@color/accent"
    app:borderWidth="0dp"
    app:elevation="4sp"/>

爪哇

FloatingActionButton mFab = (FloatingActionButton) v.findViewById(R.id.fab);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
    ViewGroup.MarginLayoutParams p = (ViewGroup.MarginLayoutParams) mFab.getLayoutParams();
    p.setMargins(0, 0, dpToPx(getActivity(), 8), 0); // get rid of margins since shadow area is now the margin
    mFab.setLayoutParams(p);
}

将 dp 转换为 px

public static int dpToPx(Context context, float dp) {
    // Reference http://stackoverflow.com/questions/8309354/formula-px-to-dp-dp-to-px-android
    float scale = context.getResources().getDisplayMetrics().density;
    return (int) ((dp * scale) + 0.5f);
}

棒糖

在此处输入图像描述

前棒棒糖

在此处输入图像描述

于 2015-06-06T22:22:39.777 回答
8

On pre LollipopFloatingActionButton负责绘制自己的阴影。因此,视图必须稍大一些才能为阴影腾出空间。要获得一致的行为,您可以设置边距以考虑高度和宽度的差异。我目前正在使用以下课程

import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.view.ViewGroup.MarginLayoutParams;

import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.LOLLIPOP;

import static android.support.design.R.styleable.FloatingActionButton;
import static android.support.design.R.styleable.FloatingActionButton_fabSize;
import static android.support.design.R.style.Widget_Design_FloatingActionButton;
import static android.support.design.R.dimen.fab_size_normal;
import static android.support.design.R.dimen.fab_size_mini;

public class CustomFloatingActionButton extends FloatingActionButton {

    private int mSize;

    public CustomFloatingActionButton(Context context) {
        this(context, null);
    }

    public CustomFloatingActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CustomFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, FloatingActionButton, defStyleAttr,
                Widget_Design_FloatingActionButton);
        this.mSize = a.getInt(FloatingActionButton_fabSize, 0);
        a.recycle();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (SDK_INT < LOLLIPOP) {
            int size = this.getSizeDimension();
            int offsetVertical = (h - size) / 2;
            int offsetHorizontal = (w - size) / 2;
            MarginLayoutParams params = (MarginLayoutParams) getLayoutParams();
            params.leftMargin = params.leftMargin - offsetHorizontal;
            params.rightMargin = params.rightMargin - offsetHorizontal;
            params.topMargin = params.topMargin - offsetVertical;
            params.bottomMargin = params.bottomMargin - offsetVertical;
            setLayoutParams(params);
        }
    }

    private final int getSizeDimension() {
        switch (this.mSize) {
            case 0: default: return this.getResources().getDimensionPixelSize(fab_size_normal);
            case 1: return this.getResources().getDimensionPixelSize(fab_size_mini);
        }
    }
}

更新: Android 支持库 v23 将 fab_size dimens 重命名为:

import static android.support.design.R.dimen.design_fab_size_normal;
import static android.support.design.R.dimen.design_fab_size_mini;
于 2015-06-15T12:27:01.470 回答
5

在更新到 v23.1.0 并对导入进行一些调整后,Markus 的回答对我来说效果很好(使用最近的 gradle 插件,我们使用我们的应用程序 R 而不是设计库的 R)。这是 v23.1.0 的代码:

// Based on this answer: https://stackoverflow.com/a/30845164/1317564
public class CustomFloatingActionButton extends FloatingActionButton {
    private int mSize;

    public CustomFloatingActionButton(Context context) {
        this(context, null);
    }

    public CustomFloatingActionButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("PrivateResource")
    public CustomFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.FloatingActionButton, defStyleAttr,
                R.style.Widget_Design_FloatingActionButton);
        mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, 0);
        a.recycle();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            int size = this.getSizeDimension();
            int offsetVertical = (h - size) / 2;
            int offsetHorizontal = (w - size) / 2;
            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
            params.leftMargin = params.leftMargin - offsetHorizontal;
            params.rightMargin = params.rightMargin - offsetHorizontal;
            params.topMargin = params.topMargin - offsetVertical;
            params.bottomMargin = params.bottomMargin - offsetVertical;
            setLayoutParams(params);
        }
    }

    @SuppressLint("PrivateResource")
    private int getSizeDimension() {
        switch (mSize) {
            case 1:
                return getResources().getDimensionPixelSize(R.dimen.design_fab_size_mini);
            case 0:
            default:
                return getResources().getDimensionPixelSize(R.dimen.design_fab_size_normal);
        }
    }
}
于 2015-10-16T22:59:21.460 回答
3

在布局文件中将属性高程设置为 0。因为它采用默认高程。

app:elevation="0dp"

现在在活动中检查 API 级别是否大于 21 并在需要时设置海拔。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    fabBtn.setElevation(10.0f);
}
于 2016-11-10T06:00:12.570 回答