Androidデザインライブラリ-フローティングアクションボタンのパディング/マージンの問題


109

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はなぜパディング/マージンが非常に大きいのですか?


1
を使用CoordinatorLayoutして垂直方向に位置合わせし、追加のパディングプレロリポップを目で確認することをお勧めします。逆コンパイルされたFABソースからそれを理解することもできますが、Googleがそれを修正したのと同じように、Googleが修正するのを待ちCardViewます。
DariusL 2015

回答:


129

アップデート(2016年10月):

ここでの正しい解決策はapp:useCompatPadding="true"、FloatingActionButton に配置することです。これにより、異なるAPIバージョン間でパディングが一貫します。ただし、これでもデフォルトのマージンが少しずれているように見えるため、それらを調整する必要がある場合があります。ただし、少なくともAPI固有のスタイルは必要ありません。

以前の答え:

これは、API固有のスタイルを使用して簡単に実現できます。通常はvalues/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では、ボタンはビューの幅に寄与しない新しい標高パラメーターを使用します。


19
バギーAndroid .. :(
Abdullah Shoaib '13 / 09/15

3
途方もなく醜い見えますが、他の解決策が存在しないようだ
11

3
良い答え、ありがとうございます。それを編集してタブレット用のスタイルを追加することを提案できますか?API> = 20の場合、マージンは24 dpです。API <20の場合、<item name = "android:layout_marginRight"> 12dp </ item> <item name = "android:layout_marginBottom"> 6dp </ item>が必要であることに気付きました。アプリで必要だったので、自分で計算する必要がありました。スタイルの代わりにdimensリソースを使用することもできます。
JJ86

マージン番号はelevation、FABでの設定に応じて異なります。
Jarett Millard、2016

使用app:useCompatPadding="true"
Kishan Vaghela

51

ファイルをいじっstyles.xmlたりいじったりする必要はもうありません.java。簡単にしましょう。

app:useCompatPadding="true"カスタムマージンを使用および削除して、Androidの異なるバージョン間で同じマージンを維持できます。

あなたは第二画像にFABで見た余分なマージン/パディングが原因これにあるcompatPadding前ロリポップデバイス。このプロパティが設定されていない場合、それは上適用されます前lollopopデバイスと、NOTロリポップ+デバイスで。

android studioコード

コンセプトの証明

デザインビュー


親のレイアウトがカードビューの場合、fabには "card_view:useCompatPadding =" true "を使用する必要があります
Amit Tumkur

これは、サポートライブラリをバージョン23.2にアップグレードすると機能します。ありがとう!
パブロ

あなたのPoCにマージンが見えます。
ペドロオリベイラ

@PedroOliveiraはい、Androidのすべてのバージョンで同じマージンが表示されますが、これが実際の目的です。
サラバナバラギラマチャンドラン2016年

1
彼は「xxx」を使用してカスタムマージンを削除できると言っていますが、OPが理由を尋ねたように、概念実証はすべてのマージンを示しています。
ペドロオリベイラ

31

数回の検索とソリューションのテストの後、この行を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" />

2
すばらしい、私のために働いた。どちらuseCompatPaddingも同じ結果を得ることはありません。
bgplaya 2017年

1
この回答とビクラムの
ingkevin

22

デザインサポートライブラリ内に問題があります。以下の方法を使用して、ライブラリが更新されるまでこの問題を修正します。このコードをアクティビティまたはフラグメントに追加して、問題を解決してください。xmlは同じにしてください。ロリポップ以上ではマージンはありませんが、その下には16 dpのマージンがあります。

作業例の更新

XML-FABはRelativeLayout内にあります

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

ロリポップ

ここに画像の説明を入力してください

ロリポップ前

ここに画像の説明を入力してください


これが正解です。ただし、パディングも非正方形であるため、問題は100%修正されません。
JohnnyLambada 2015年

@JohnnyLambada私はそうは思いません。RelativeLayout.LayoutParamsキャストすることができないLayoutParamsFloatingActionButtonと私は前ロリポップに16dpの任意の余白が表示されません。FloatingActionButtonLollipop以前の幅は56 dpではなく84 dpで、高さは98 dpです。
Markus Rubey

@MarkusRubey実例と、ロリポップ前バージョンとロリポップバージョンを表示する画像を使用して、回答を更新します。
ユージンH

1
@MarkusRubey- is inのタイプのView.getLayoutParamsa LayoutParamsを返します。Eugene Viewの場合はRelativeLayout.LayoutParamsです。
JohnnyLambada

1
@EugeneH RelativeLayout.LayoutParamsをViewGroup.MarginLayoutParamsに変更しました。これにより、コードがより多くのケースで機能し、MarkusRubeyがもたらす問題が修正されます。
JohnnyLambada 2015年

8

以前のLollipop FloatingActionButtonは、独自の影を描く責任があります。したがって、ビューは影のためのスペースを作るために少し大きくする必要があります。一貫した動作を得るために、高さと幅の違いを考慮してマージンを設定できます。私は現在次のクラスを使用しています:

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;

プロジェクトをAndroidXにリファクタリングしたところ、例から3番目のコンストラクタを作成できません。AndroidXライブラリを使用してどうすればよいですか?
アロンシュライダー

5

Markusの答えは、v23.1.0に更新してインポートにいくつかの調整を行った後、うまく機能しました(最近の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);
        }
    }
}

AndroidXにリファクタリングした後は、この例を使用できないようです-3番目のコンストラクターはコンパイルできなくなりました。何が悪いのか知っていますか?
アロンシュライダー

3

レイアウトファイルでは、属性の標高を0に設定します。これは、デフォルトの標高が使用されるためです。

app:elevation="0dp"

アクティビティで21より大きいAPIレベルを確認し、必要に応じて標高を設定します。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
    fabBtn.setElevation(10.0f);
}

compatライブラリを使用している場合は、setCompatElevationを使用します。そして、直接ピクセルの代わりにディップを使用する方が良いでしょう。
ingkevin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.