android - icon - floating action button library
Biblioteca de diseño de Android: problemas de margen de relleno/botón de acción flotante (7)
Estoy usando el nuevo FloatingActionButton de la Biblioteca de diseño de Google y obtengo algunos problemas extraños de relleno / margen. Esta imagen (con opciones de diseño para desarrolladores activadas) es de API 22.
Y de API 17.
Este es el 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"/>
¿Por qué el FAB en API 17 es un relleno / margen mucho más grande?
En el archivo de diseño, establezca la elevación del atributo en 0. porque toma la elevación predeterminada.
app:elevation="0dp"
Ahora en actividad, verifique el nivel de API superior a 21 y configure la elevación si es necesario.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
fabBtn.setElevation(10.0f);
}
En pre Lollipop
FloatingActionButton
es responsable de dibujar su propia sombra.
Por lo tanto, la vista tiene que ser un poco más grande para hacer espacio para la sombra.
Para obtener un comportamiento coherente, puede establecer márgenes para tener en cuenta la diferencia en altura y anchura.
Actualmente estoy usando la siguiente
class
:
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);
}
}
}
Actualización: Las bibliotecas de soporte de Android v23 cambiaron el nombre de fab_size dimens a:
import static android.support.design.R.dimen.design_fab_size_normal;
import static android.support.design.R.dimen.design_fab_size_mini;
Hay un problema dentro de la Biblioteca de soporte de diseño. Utilice el siguiente método para solucionar este problema hasta que se actualice la biblioteca. Intente agregar este código a su actividad o fragmento para resolver el problema. Mantenga su xml igual. En lollipop y arriba no hay margen, pero debajo hay un margen de 16dp.
Actualizar ejemplo de trabajo
XML: FAB está dentro de un diseño relativo
<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 a px
public static int dpToPx(Context context, float dp) {
// Reference http://.com/questions/8309354/formula-px-to-dp-dp-to-px-android
float scale = context.getResources().getDisplayMetrics().density;
return (int) ((dp * scale) + 0.5f);
}
Pirulí
Pre Lollipop
después de un tiempo de búsqueda y solución de prueba, solucioné mi problema al agregar esta línea solo a mi diseño xml:
app:elevation="0dp"
app:pressedTranslationZ="0dp"
y este es todo mi diseño de botón flotante
<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" />
La respuesta de Markus funcionó bien para mí después de actualizar a v23.1.0 y hacer algunos ajustes a las importaciones (con el reciente complemento de gradle usamos nuestra aplicación R en lugar de la R de la biblioteca de diseño). Aquí está el código para v23.1.0:
// Based on this answer: https://.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);
}
}
}
Actualización (octubre de 2016):
La solución correcta ahora es poner la
app:useCompatPadding="true"
en su FloatingActionButton.
Esto hará que el relleno sea consistente entre diferentes versiones de API.
Sin embargo, esto todavía parece disminuir un poco los márgenes predeterminados, por lo que es posible que deba ajustarlos.
Pero al menos ya no hay necesidad de estilos específicos de API.
Respuesta anterior:
Puede lograr esto fácilmente utilizando estilos específicos de API.
En sus
values/styles.xml
normales, ponga algo como esto:
<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>
y luego en valores-v21 / styles.xml, use esto:
<style name="floating_action_button">
<item name="android:layout_margin">16dp</item>
</style>
y aplica el estilo a tu FloatingActionButton:
<android.support.design.widget.FloatingActionButton
...
style="@style/floating_action_button"
...
/>
Como otros han señalado, en API <20, el botón genera su propia sombra, lo que se suma al ancho lógico general de la vista, mientras que en API> = 20 usa los nuevos parámetros de Elevación que no contribuyen al ancho de la vista.
No más
styles.xml
con
styles.xml
o con archivos
.java
.
Déjame hacerlo simple.
Puede usar la
app:useCompatPadding="true"
y eliminar márgenes personalizados para mantener los mismos márgenes en diferentes versiones de Android
El margen / relleno adicional que vio en el FAB en su segunda imagen se debe a este compatPadding en dispositivos pre-lollipop . Si no se establece esta propiedad, se aplica en dispositivos pre-lollopop y NO en dispositivos lollipop +.
Prueba de concepto