How to do this Scroll hide fab button in Jetpack Compose with transaction
Like this I need it:
You can use NestedScrollConnection
and AnimatedVisibility
to change visibilty of ExtendedFloatingActionButton
.
remeberSaveable
to store state of ExtendedFloatingActionButton
:// Visibility for FAB, could be saved in viewModel
val isVisible = rememberSaveable { mutableStateOf(true) }
NestedScrollConnection
, you can use your values to show/hide FAB:// Nested scroll for control FAB
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
// Hide FAB
if (available.y < -1) {
isVisible.value = false
}
// Show FAB
if (available.y > 1) {
isVisible.value = true
}
return Offset.Zero
}
}
}
ExtendedFloatingActionButton
inside AnimatedVisibility
, set visible value from isVisible
and set enter and exit animation, in my case I use slideInVertically
for enter animation and slideOutVertically
for exit animation:AnimatedVisibility(
visible = isVisible.value,
enter = slideInVertically(initialOffsetY = { it * 2 }),
exit = slideOutVertically(targetOffsetY = { it * 2 }),
) {
ExtendedFloatingActionButton(
onClick = {
// FAB click
}
) {
Text(
text = "Extended FAB"
)
}
}
NestedScrollConnection
to scrollable content, in my case to LazyColumn
:LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(innerPadding)
.nestedScroll(nestedScrollConnection),
) {
items(100) { index ->
Text(
modifier = Modifier.padding(16.dp),
text = "Item: $index"
)
}
}
Full code of MainActivity:
package com.andreirozov.animatedfab
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.slideInHorizontally
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutHorizontally
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Add
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExtendedFloatingActionButton
import androidx.compose.material3.FabPosition
import androidx.compose.material3.FloatingActionButton
import androidx.compose.material3.Icon
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.unit.dp
import com.andreirozov.animatedfab.ui.theme.AnimatedFabTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
AnimatedFabApp()
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AnimatedFabApp() {
AnimatedFabTheme {
// Visibility for FAB, could be saved in viewModel
val isVisible = rememberSaveable { mutableStateOf(true) }
// Nested scroll for control FAB
val nestedScrollConnection = remember {
object : NestedScrollConnection {
override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
// Hide FAB
if (available.y < -1) {
isVisible.value = false
}
// Show FAB
if (available.y > 1) {
isVisible.value = true
}
return Offset.Zero
}
}
}
Scaffold(
floatingActionButtonPosition = FabPosition.Center,
floatingActionButton = {
AnimatedVisibility(
visible = isVisible.value,
enter = slideInVertically(initialOffsetY = { it * 2 }),
exit = slideOutVertically(targetOffsetY = { it * 2 }),
) {
ExtendedFloatingActionButton(
onClick = {
// FAB click
}
) {
Text(
text = "Extended FAB"
)
}
}
}
) { innerPadding ->
LazyColumn(
modifier = Modifier
.fillMaxWidth()
.padding(innerPadding)
.nestedScroll(nestedScrollConnection),
) {
items(100) { index ->
Text(
modifier = Modifier.padding(16.dp),
text = "Item: $index"
)
}
}
}
}
}
Result: