You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jetpack Compose中PullToRefreshBox返回或滑动后消失问题求助

问题描述
  • 返回页面后异常:离开当前页面再返回时,若刷新任务正在进行,滚动或点击屏幕会导致刷新指示器立即消失;
  • 滑动异常:上下滑动屏幕时,刷新指示器会意外消失。

问题演示:
问题演示动图

相关代码

@AndroidEntryPoint
class TestActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyApp()
        }
    }
}

@Composable
fun MyApp() {
    // 定义路由及对应图标
    val topLevelRoutes = listOf(
        TopLevelRoute("Profile", "profile", Icons.Filled.AccountCircle),
        TopLevelRoute("Friends", "friends", Icons.Filled.People)
    )

    // 创建NavController
    val navController = rememberNavController()

    Scaffold(
        bottomBar = {
            BottomNavigation {
                val navBackStackEntry by navController.currentBackStackEntryAsState()
                val currentDestination = navBackStackEntry?.destination
                topLevelRoutes.forEach { topLevelRoute ->
                    BottomNavigationItem(
                        icon = {
                            Icon(
                                topLevelRoute.icon,
                                contentDescription = topLevelRoute.name
                            )
                        },
                        label = { Text(topLevelRoute.name) },
                        selected = currentDestination?.route == topLevelRoute.route,
                        onClick = {
                            navController.navigate(topLevelRoute.route) {
                                popUpTo(navController.graph.findStartDestination().id) {
                                    saveState = true
                                }
                                launchSingleTop = true
                                restoreState = true
                            }
                        }
                    )
                }
            }
        }
    ) { innerPadding ->
        NavHost(navController, startDestination = "profile", Modifier.padding(innerPadding)) {
            composable("profile") { ProfileScreen() }
            composable("friends") { FriendsScreen() }
        }
    }
}

data class TopLevelRoute(val name: String, val route: String, val icon: ImageVector)

@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Composable
fun ProfileScreen() {

    var isRefreshing by rememberSaveable { mutableStateOf(false) }

    // 刷新开始时启动协程
    if (isRefreshing) {
        LaunchedEffect(Unit) {
            delay(10000) // 模拟网络请求
            isRefreshing = false // 重置刷新状态
        }
    }

    // 个人资料页面内容
    Surface {
        PullToRefreshBox(
            onRefresh = { isRefreshing = true },
            isRefreshing = isRefreshing,
            modifier = Modifier
                .fillMaxSize()
        ) {
            Column(
                modifier = Modifier
                    .fillMaxSize()
                    .verticalScroll(rememberScrollState()),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally,

                ) {
                // 主内容区
                Text("Profile Screen", style = MaterialTheme.typography.h4)
            }
        }
    }
}

@Composable
fun FriendsScreen() {
    // 好友页面内容
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Text("Friends Screen")
    }
}
解决方案

问题根源

  1. 原代码中只要isRefreshing为true就会创建LaunchedEffect(Unit),页面重建(比如返回页面)时会重复启动协程,导致isRefreshing被提前置为false;
  2. Column + verticalScroll的滚动手势与PullToRefreshBox的下拉刷新手势存在冲突,滑动时会干扰刷新指示器的状态维持。

修复步骤

1. 正确管理刷新协程

将LaunchedEffect的触发条件改为isRefreshing,确保每次仅启动一个协程执行刷新逻辑,避免重复触发:

LaunchedEffect(isRefreshing) {
    if (isRefreshing) {
        delay(10000) // 模拟网络请求
        isRefreshing = false
    }
}

替换原代码中if (isRefreshing) { LaunchedEffect(Unit) { ... } }的结构。

2. 解决手势冲突

使用LazyColumn替代Column + verticalScroll,PullToRefreshBox与LazyColumn的手势兼容性更好,能避免滑动时的状态干扰:

PullToRefreshBox(
    onRefresh = { isRefreshing = true },
    isRefreshing = isRefreshing,
    modifier = Modifier.fillMaxSize()
) {
    LazyColumn(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        item {
            Text("Profile Screen", style = MaterialTheme.typography.h4)
        }
        // 可添加更多列表项
    }
}

完整修复后的ProfileScreen代码

@OptIn(ExperimentalMaterialApi::class, ExperimentalMaterial3Api::class)
@Composable
fun ProfileScreen() {

    var isRefreshing by rememberSaveable { mutableStateOf(false) }

    LaunchedEffect(isRefreshing) {
        if (isRefreshing) {
            delay(10000) // 模拟网络请求
            isRefreshing = false
        }
    }

    Surface {
        PullToRefreshBox(
            onRefresh = { isRefreshing = true },
            isRefreshing = isRefreshing,
            modifier = Modifier.fillMaxSize()
        ) {
            LazyColumn(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                item {
                    Text("Profile Screen", style = MaterialTheme.typography.h4)
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Santhosh Kumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 20:40:24