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.
Et de l'API 17.
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?
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.
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.
Preuve de concept
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" />
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
pré sucette
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;
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);
}
}
}
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);
}