I want to build a screen using only Material3
components and Jetpack Compose. When I combine the MediumTopAppBar
with a PullToRefreshBox
and the exitUntilCollapsedScrollBehavior
it intercepts my scroll while the TopAppBar is not fully expanded yet. How can I prevent this?
MaterialTheme {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
contentWindowInsets = WindowInsets.safeContent,
topBar = { MediumTopAppBar(title = { Text("Title") }, scrollBehavior = scrollBehavior) },
) { padding ->
val coroutineScope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
val state: PullToRefreshState = rememberPullToRefreshState()
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = {
isRefreshing = true
coroutineScope.launch {
delay(3.seconds)
isRefreshing = false
}
},
state = state,
indicator = {
Indicator(
modifier = Modifier
.align(Alignment.TopCenter)
.padding(padding),
isRefreshing = isRefreshing,
state = state,
)
},
) {
ListItems(padding)
}
}
}
I want to build a screen using only Material3
components and Jetpack Compose. When I combine the MediumTopAppBar
with a PullToRefreshBox
and the exitUntilCollapsedScrollBehavior
it intercepts my scroll while the TopAppBar is not fully expanded yet. How can I prevent this?
MaterialTheme {
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
contentWindowInsets = WindowInsets.safeContent,
topBar = { MediumTopAppBar(title = { Text("Title") }, scrollBehavior = scrollBehavior) },
) { padding ->
val coroutineScope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
val state: PullToRefreshState = rememberPullToRefreshState()
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = {
isRefreshing = true
coroutineScope.launch {
delay(3.seconds)
isRefreshing = false
}
},
state = state,
indicator = {
Indicator(
modifier = Modifier
.align(Alignment.TopCenter)
.padding(padding),
isRefreshing = isRefreshing,
state = state,
)
},
) {
ListItems(padding)
}
}
}
Share
Improve this question
asked Mar 27 at 16:30
WirlingWirling
5,4353 gold badges52 silver badges83 bronze badges
2
|
1 Answer
Reset to default 0Please try to pull the PullToRefreshBox
outside of the Scaffold
like this:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun ScaffoldComposable() {
val coroutineScope = rememberCoroutineScope()
var isRefreshing by remember { mutableStateOf(false) }
val state: PullToRefreshState = rememberPullToRefreshState()
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
PullToRefreshBox(
isRefreshing = isRefreshing,
onRefresh = {
isRefreshing = true
coroutineScope.launch {
delay(3.seconds)
isRefreshing = false
}
},
state = state,
indicator = {
Indicator(
modifier = Modifier
.align(Alignment.TopCenter),
isRefreshing = isRefreshing,
state = state,
)
}
) {
Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
MediumTopAppBar(
title = { Text("Title") },
scrollBehavior = scrollBehavior
)
},
) { padding ->
LazyColumn(
modifier = Modifier.padding(padding)
) {
items(100) {
Text(modifier = Modifier.fillMaxWidth(), text = "Item $it")
}
}
}
}
}
Then, the PullToRefreshBox
can only consume any scroll deltas that were not consumed by the Scaffold
, meaning that the Indicator
will only appear once the MediumTopAppBar
is fully expanded.
If you still want the indicator to appear below the MediumTopAppBar
, you can apply a padding
Modifier as follows:
indicator = {
Indicator(
modifier = Modifier
.padding(top = TopAppBarDefaults.MediumAppBarExpandedHeight)
.align(Alignment.TopCenter),
isRefreshing = isRefreshing,
state = state,
)
}
Output:
ListItems
. – askSoap Commented Mar 29 at 7:57