如何避免 Jetpack Compose 中的 onClick 回调被多次调用

huangapple go评论75阅读模式
英文:

How to Avoid onClick callback being called multiple times Jetpack Compose

问题

在测试我的应用程序时,我意识到如果用户快速多次按下FloatingActionButtononClick回调可能会被多次触发。在我的情况下,这会导致返回栈多次弹出,因为onPopBackStack回调会冒泡到NavHost,在那里它可以访问navController并调用popBackStack方法。

fun AddEditTodoScreen(onPopBackStack: () -> Unit, viewModel: AddEditTodoViewModel = viewModel()) {

    var isNavigating by remember{
        mutableStateOf(false)
    }

    LaunchedEffect(key1 = true){
        viewModel.uiEvent.collect{event : UiEvent ->
            when(event){
                is UiEvent.PopBackStack -> onPopBackStack()
                else -> Unit
            }
        }
    }

    Scaffold(floatingActionButton = {
        FloatingActionButton(onClick = {
            if(!isNavigating){
                isNavigating = true
                onPopBackStack()
            }
        }) {
            Icon(imageVector = Icons.Default.Check, contentDescription = "Check")
        }
    })
}

目前,我只是在首次点击FloatingActionButton时将isNavigating设置为true,如果再次点击,它会检查isNavigating标志是否为true,如果是,则不执行任何操作。是否有更好的方法来解决这个问题呢?

英文:

While testing my app I realized that if a user pressed the FloatingActionButton quickly, several times, the onClick call back could be fired multiple times. In my case, this caused the backstack being popped multiple times, as the onPopBackStack callback bubbles up to the NavHost where it has access to the navController and ivokes the popBackStack method.

fun AddEditTodoScreen(onPopBackStack: () -> Unit, viewModel: AddEditTodoViewModel = viewModel()) {

    var isNavigating by remember{
        mutableStateOf(false)
    }

    LaunchedEffect(key1 = true){
        viewModel.uiEvent.collect{event : UiEvent ->
            when(event){
                is UiEvent.PopBackStack -> onPopBackStack
                else -> Unit
            }
        }
    }

    Scaffold(floatingActionButton = {
        FloatingActionButton(onClick = {
            if(!isNavigating){
                isNavigating = !isNavigating
                onPopBackStack()
            }
        }) {
            Icon(imageVector = Icons.Default.Check, contentDescription = "Check")
        }

Currently I'm just setting a isNavigating to true when the FloatingActionButton is first clicked and if clicked again, it checks if the isNavigating flag is set to true, if so it does nothing. What would be a better way, if any, to address this?

答案1

得分: 14

导航已经告诉您是否正在导航到新目标:当您调用navigate时,NavBackStackEntryLifecycle会同步更改,将您从RESUMED状态移动下来。

因此,如果您希望在已经开始导航到另一个屏幕后避免处理点击事件,您需要检查LocalLifecycleOwner的状态:

// 这与与此屏幕关联的NavBackStackEntry相对应
val lifecycleOwner = LocalLifecycleOwner.current

FloatingActionButton(onClick = {
    // 获取Lifecycle的当前状态
    val currentState = lifecycleOwner.lifecycle.currentState

    // 当您已经开始导航到另一个屏幕时,请忽略点击事件
    if (currentState.isAtLeast(Lifecycle.State.RESUMED)) {
        onPopBackStack()
    }
}
英文:

Navigation already tells you if you're navigating to a new destination: the Lifecycle of the NavBackStackEntry is synchronously changed when you call navigate, moving you down from the RESUMED state.

Therefore if you want to avoid handling clicks after you've already started navigating to another screen, you'd want to check the LocalLifecycleOwner's state:

// This corresponds with the NavBackStackEntry
// associated with this screen
val lifecycleOwner = LocalLifecycleOwner.current

FloatingActionButton(onClick = {
    // Get the current state of the Lifecycle
    val currentState = lifecycleOwner.lifecycle.currentState

    // And ignore click events when you've started navigating
    // to another screen
    if (currentState.isAtLeast(Lifecycle.State.RESUMED)) {
        onPopBackStack()
    }
}

huangapple
  • 本文由 发表于 2023年6月2日 08:22:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76386471.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定