Icono del sitio Develou

Floating Action Button En Compose

En este tutorial estudiaremos cómo usar el componente Floating Action Button en Compose. Comúnmente se le abrevia como FAB. Su función es representar a la acción principal en una pantalla de tu App, de forma que destaque ante los demás elementos de su alrededor. Y a diferencia de los botones normales, se posiciona en frente de todo el contenido de la pantalla.

La siguiente tabla de contenido muestra la ruta a seguir para el uso del FAB

Ejemplos De Floating Action Button En Compose

Puedes encontrar todos los códigos de ejemplo usados en el paquete Floating_Action_Button del módulo p7_componentes, en el repositorio de GitHub.

Verás que existe un archivo Kotlin con todas las funciones componibles de ejemplo que se enuncian en cada sección de este tutorial.


1. Tipos De Floating Action Button

Floating Action Button Regular

El FAB regular posee un contenedor que es circular por defecto y cuyo color de relleno se define por el color primario del tema aplicado en la función componible donde vive. Además, representa su acción con un icono en su centro.

Para crear uno, usa la función FloatingActionButton con los siguientes parámetros:

@Composable
fun FloatingActionButton(
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
    backgroundColor: Color = MaterialTheme.colors.secondary,
    contentColor: Color = contentColorFor(backgroundColor),
    elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation(),
    content: () -> Unit
): @Composable Unit

Ahora bien, dependiendo del tamaño del contenedor del FAB regular, este se clasifica en Default y Mini.

Default FAB

El tamaño del Default FAB es de 56 x 56dp y se usa en pantallas con más anchos mayores a 460dp.

Por ejemplo:

Crear un FAB con un icono que represente la acción de abrir una pantalla de creación de una nota.

@Composable
fun DefaultFloatingActionButtonExample() {
    FloatingActionButton(onClick = { /* Tus acciones */ }) {
        Icon(imageVector = Icons.Default.Add, contentDescription = "Crear nota")
    }
}

El FAB toma en su parámetro content un componente Icon para establecer la imagen que será usada para enfatizar su acción. En este caso Icons.Default.Add simboliza perfectamente la creación.

Mini FAB

El tamaño del contenedor de un mini FAB es de 40 x 40 dp, por lo que debes usarlo en pantallas con anchos menores o iguales a 460dp.

Para conseguir esas dimensiones, usa el parámetro modifier junto al modificador size():

@Composable
fun MiniFloatingActionButtonExample() {
    val miniFabSize = 40.dp
    FloatingActionButton(
        onClick = { /* Tus acciones */ },
        modifier = Modifier.size(miniFabSize)
    ) {
        Icon(imageVector = Icons.Default.Add, contentDescription = "Crear nota")
    }
}

Extended Floating Action Button

El FAB extendido dispone de un contenedor más grande que el del regular, ya que posee una etiqueta de texto para hacer explícita la acción principal.

Crea este tipo de FAB con la función ExtendedFloatingActionButton:

@Composable
fun ExtendedFloatingActionButton(
    text: () -> Unit,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    icon: () -> Unit = null,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
    backgroundColor: Color = MaterialTheme.colors.secondary,
    contentColor: Color = contentColorFor(backgroundColor),
    elevation: FloatingActionButtonElevation = FloatingActionButtonDefaults.elevation()
): @Composable Unit

Como ves, a comparación del FAB regular, la firma del extendido trae el parámetro text para la etiqueta de texto (obligatoria) y a icon para el icono opcional.

Ejemplo:

Crear un extended FAB con la acción de compartir una foto de una pantalla.

@Composable
fun ExtendedFloatingActionButtonExample() {
    ExtendedFloatingActionButton(
        text = { Text("COMPARTIR") },
        onClick = { /* Tus acciones */ },
        icon = {
            Icon(
                imageVector = Icons.Default.Share,
                contentDescription = "Compartir foto"
            )
        })
}

2. Posicionar FAB Con Scaffold

Hasta el momento hemos ubicado el FloatingActionButton arbitrariamente sin tener en cuenta la estructura visual de un layout en los lineamientos del Material Design.

Para asegurar que la posición del FAB esté sobre el contenido y trabaje en comunión con otros componentes, crearemos un componente Scaffold (todo).

Este provee los atributos floatingActionButton y floatingActionButtonPosition para armonizar el FAB junto a otros componentes (App bars (todo), Snackbars (todo), Drawer (todo), etc.)

Ejemplo:

Ubicar un FAB regular en la parte inferior derecha de la pantalla:

@Composable
fun FABInScaffoldExample() {
    Scaffold(
        topBar = {
            TopAppBar { }
        },
        floatingActionButton = {
            FloatingActionButton(onClick = { /* Tus acciones */ }) {
                Icon(
                    imageVector = Icons.Default.Add,
                    contentDescription = "Crear nota"
                )
            }
        },
        floatingActionButtonPosition = FabPosition.End
    ) {
        Box(
            modifier = Modifier.fillMaxSize(),
            contentAlignment = Alignment.Center
        ) {
            Text("Floating Action Button En Scaffold")
        }
    }
}

Como ves, la parte inferior derecha es representada por el valor FabPosition.End. También puedes usar FabPosition.Center para posicionar al FAB en el centro de la parte inferior.

El Scaffold ajustará la profundidad del dibujado para que el FAB se encuentre por encima del contenido descrito en el lambda, en este caso es un layout Box con un componente Text en su interior.


3. Estilizar FAB

Veamos cómo personalizar la forma, colores y tipografía de un Floating Action Button.

Cambiar Forma

Al igual que la mayoría de componentes, el parámetro shape determina la forma de las cuatro esquinas del FAB. Lo que quiere decir que usaremos las clases RoundedCornerShape y CutCornerShape para generar el recorte que necesitemos.

Ejemplo:

Modificar la forma de un FAB regular para conseguir un diamante y un rectángulo con esquinas cortadas. Asimismo, convertir en un FAB extendido en un rectángulo perfecto.

@Composable
fun FABShapeExample() {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        FloatingActionButton(onClick = {}, shape = CutCornerShape(50.dp)) {
            Icon(imageVector = Icons.Default.Edit, contentDescription = "Editar")
        }

        Spacer(Modifier.size(16.dp))

        FloatingActionButton(onClick = {}, shape = CutCornerShape(4.dp)) {
            Icon(imageVector = Icons.Default.Star, contentDescription = "Añadir a favoritos")
        }

        Spacer(Modifier.size(16.dp))

        ExtendedFloatingActionButton(text = { Text("ADJUNTAR") },
            onClick = { },
            shape = RoundedCornerShape(
                ZeroCornerSize
            ),
            icon = {
                Icon(
                    painter = painterResource(R.drawable.ic_attachment),
                    contentDescription = "Adjuntar"
                )
            }
        )
    }
}

Cambiar Colores

Ambos tipos de FABs poseen dos atributos asociados al color del fondo (colorBackground) y el del contenido (contentColor).

Por defecto, el color de relleno del background es aquel definido en MaterialTheme.colors.secondary en tu tema. Para el contenido el color será MateriaTheme.colors.onSecondary.

Ejemplo:

Crear un FAB regular con un color de fondo Naranja 400 y blanco para su contenido. También crear un FAB extendido con Azul 100 de fondo y Azul 900 de contenido.

@Composable
fun FABColorsExample() {
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        FloatingActionButton(
            onClick = {}, backgroundColor = Color(0xFFFFA726),
            contentColor = Color.White
        ) {
            Icon(
                imageVector = Icons.Default.ShoppingCart,
                contentDescription = "Añadir a carrito"
            )
        }

        Spacer(Modifier.size(16.dp))

        ExtendedFloatingActionButton(
            text = { Text("AGENDAR") },
            onClick = { },
            backgroundColor = Color(0xFFBBDEFB),
            contentColor = Color(0xFF0D47A1)
        )
    }
}

Cambiar Tipografía De Extended FAB

En el caso del extended FAB, el cambio de tipografía se realiza directamente en el componente Text que se pasa en la función.

Nota: Aprende más sobre el cambio de estilo de un texto en Texto En Compose.

Ejemplo:

Crear un FAB extendido cuya etiqueta de texto use la fuente Nunito y esté en negrilla.

@ExperimentalUnitApi
@Composable
fun FABTypographyExample() {
    ExtendedFloatingActionButton(
        text = {
            val nunitoFontFamily = FontFamily(Font(R.font.nunito_bold, FontWeight.Bold))
            val style = MaterialTheme.typography.button.copy(
                fontFamily = nunitoFontFamily,
                fontSize = 13.sp,
                letterSpacing = TextUnit(1.25f, TextUnitType.Sp)
            )
            Text("GUARDAR", style = style)
        },
        icon = {
            Icon(
                painter = painterResource(R.drawable.ic_save),
                contentDescription = "Guardar cambios"
            )
        },
        onClick = { }
    )
}

En el ejemplo anterior tomamos la ventaja de la escala tipográfica MaterialTheme.typography.button a fin de copiar la mayoría de propiedades del estilo para botones. Por lo que al usar el método copy() solo pasamos los valores fontFamily, fontSize y letterSpacing.

Salir de la versión móvil