admin管理员组

文章数量:1357665

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
  • You could try applying the nested scroll modifier on your ListItems. – askSoap Commented Mar 29 at 7:57
  • @Wirling Does below answer resolve your issue? – BenjyTec Commented Mar 31 at 4:06
Add a comment  | 

1 Answer 1

Reset to default 0

Please 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:

本文标签: androidMaterial3 PullToRefreshBox prevents TopAppBar from expandingStack Overflow