web-dev-qa-db-fra.com

Android Bibliothèque de conception - Problème de bourrage / marge du bouton d'action flottante

J'utilise le nouveau FloatingActionButton de Google Design Library et j'obtiens d'étranges problèmes de remplissage/marge. Cette image (avec les options de disposition pour les développeurs activées) provient de l’API 22.

enter image description here

Et de l'API 17.

enter image description here

C'est le 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"/>

Pourquoi le FAB dans API 17 est-il tellement plus large en termes de rembourrage/marge?

108
hitch.united

Mise à jour (octobre 2016):

La bonne solution consiste maintenant à insérer app:useCompatPadding="true" dans votre FloatingActionButton. Cela rendra le remplissage cohérent entre les différentes versions de l'API. Cependant, cela semble encore réduire un peu les marges par défaut, vous devrez donc peut-être les ajuster. Mais au moins, il n'y a plus besoin de styles spécifiques à l'API.

Réponse précédente:

Vous pouvez y parvenir facilement à l'aide de styles spécifiques à l'API. Dans votre values/styles.xml normal, mettez quelque chose comme ceci:

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

puis sous values-v21/styles.xml, utilisez ceci:

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

et appliquez le style à votre FloatingActionButton:

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

Comme d'autres l'ont noté, dans l'API <20, le bouton génère sa propre ombre, ce qui ajoute à la largeur logique globale de la vue, alors que dans l'API> = 20, il utilise les nouveaux paramètres Elevation qui ne contribuent pas à la largeur de la vue.

128
Dmitry Brant

Fini le fiddling avec les fichiers styles.xml ou .Java. Laissez-moi faire simple.

Vous pouvez utiliser app:useCompatPadding="true" et supprimer les marges personnalisées pour conserver les mêmes marges dans différentes versions d'Android.

La marge/remplissage supplémentaire que vous avez vu sur le FAB dans votre deuxième image est dû à ceci compatPadding le pré-Lollipop dispositifs. Si cette propriété n'est pas définie, elle est appliquée sur les périphériques pré-lollopop et NOT dans Lollipop + périphériques.

Android studio code

Preuve de concept

design view

après quelques recherches et solutions de test, je résous mon problème en ajoutant cette ligne à ma mise en page XML uniquement:

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

et ceci est toute ma disposition de bouton float

<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" />
30
Mostafa Rostami

Il y a un problème dans la bibliothèque de support de conception. Utilisez la méthode ci-dessous pour résoudre ce problème jusqu'à ce que la bibliothèque soit mise à jour. Essayez d’ajouter ce code à votre activité ou à votre fragment pour résoudre le problème. Gardez votre XML le même. Sur Lollipop et au-dessus, il n'y a pas de marge mais en dessous, il y a une marge de 16dp.

Mise à jour de l'exemple de travail

XML - FAB est dans un 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"/>

Java

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

Convertir dp en 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);
}

sucette

enter image description here

pré sucette

enter image description here

21
Eugene H

Le pré Lollipop FloatingActionButton est chargé de dessiner sa propre ombre. Par conséquent, la vue doit être légèrement plus grande pour faire de la place pour l'ombre. Pour obtenir un comportement cohérent, vous pouvez définir des marges afin de prendre en compte les différences de hauteur et de largeur. J'utilise actuellement le classe :

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

Mise à jour: Android Bibliothèques de support v23 renommées fab_size:

import static Android.support.design.R.dimen.design_fab_size_normal;
import static Android.support.design.R.dimen.design_fab_size_mini;
8
Markus Rubey

Réponse de Markus a bien fonctionné pour moi après la mise à jour vers la v23.1.0 et certains ajustements apportés aux importations (avec le plugin Gradle récent, nous utilisons notre application R à la place de la bibliothèque de concepteurs R). Voici le code pour 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);
        }
    }
}
5
Learn OpenGL ES

Dans le fichier de mise en page, attribuez la valeur 0 à l'attribut elevation, car elle prend l'élévation par défaut.

app:elevation="0dp"

Maintenant en activité, vérifiez le niveau d'api supérieur à 21 et réglez l'altitude si nécessaire.

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