如何防止同时点击按钮时导航到两个路径?

问题描述 投票:0回答:1

我的应用程序上有 3 个屏幕(

MainScreen
Screen1
Screen2
)。
MainScreen
上有两个按钮,用于在其他屏幕上导航。

这是当前的应用程序:

我的问题是,如果我快速单击两个按钮,两个目的地都会打开。我不想要这种行为,我只想打开我首先单击的按钮的屏幕。 换句话说,

MainScreen
必须始终保留在后台,并且
Screen1
上方只能有两个屏幕之一(
Screen2
MainScreen
)。如何做到这一点?

这是代码:

MainActivity.kt

enum class Routes {
    MainScreen, Screen1, Screen2
}

sealed class UiEvent {
    data class Navigate(val route: String): UiEvent()
}

@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TestTheme {
                val navController = rememberNavController()
                NavHost(
                    navController = navController,
                    startDestination = Routes.MainScreen.name
                ) {
                    composable(route = Routes.MainScreen.name) {
                        MainScreen(onNavigate = {
                            navController.navigate(route = it.route) {
                                launchSingleTop = true
                            }
                        },)
                    }
                    composable(route = Routes.Screen1.name) {
                        Screen1()
                    }
                    composable(route = Routes.Screen2.name) {
                        Screen2()
                    }
                }
            }
        }
    }
}

@Composable
fun MainScreen(
    onNavigate: (UiEvent.Navigate) -> Unit,
    viewModel: MainViewModel = hiltViewModel()
) {
    LaunchedEffect(key1 = true) {
        viewModel.uiEvent.collectLatest { uiEvent ->
            when (uiEvent) {
                is UiEvent.Navigate -> {
                    onNavigate(uiEvent)
                }
            }
        }
    }

    Row {
        Button(onClick = { viewModel.navigateTo(Routes.Screen1) }) {
            Text(text = "Screen1")
        }
        Button(onClick = { viewModel.navigateTo(Routes.Screen2) }) {
            Text(text = "Screen2")
        }
    }
}

@Composable
fun Screen1() { Text(text = "Screen 1") }

@Composable
fun Screen2() { Text(text = "Screen 2") }

MainViewModel.kt

@HiltViewModel
class MainViewModel @Inject constructor() : ViewModel() {

    private val _uiEvent = Channel<UiEvent>()
    val uiEvent = _uiEvent.receiveAsFlow()

    fun navigateTo(route: Routes) {
        sendUiEvent(UiEvent.Navigate(route.name))
    }

    private fun sendUiEvent(event: UiEvent) {
        viewModelScope.launch {
            _uiEvent.send(event)
        }
    }
}

提前致谢。

android kotlin navigation android-jetpack-compose
1个回答
0
投票

您可以创建一个不允许在短时间内执行多次单击的按钮包装。

@Composable
fun SingleClickableComposableWrapper(
    onClick: (action: Int) -> Unit,
    content: @Composable (onClick: SingleClickHandler) -> Unit
) {
    val clickAction = remember(onClick) {
        SingleClickHandler(onClick = onClick)
    }

    content(clickAction)
}

然后像这样创建 SingleClickHandler:

class SingleClickHandler(private val onClick: (action: Int) -> Unit) {

    private val actionDisabledDuration = 650L

    private var previousActionTimestamp = 0L

    fun handleAction(action: Int = -1) {
        val currentTimestamp = Instant.now().toEpochMilli()

        val millisDiff = currentTimestamp - previousActionTimestamp
        previousActionTimestamp = currentTimestamp 

        if (millisDiff > actionDisabledDuration) {
            onClick(action)
        }
    }
}

现在您可以使用 SingleClickableComposableWrapper 包装按钮并像这样使用它:

        SingleClickableComposableWrapper(
            onClick = { action ->
               //here you can check the action and call the navigation that you want to do.
               when(action) {
                  0 -> viewModel.navigateTo(Routes.Screen1)
                  1 -> viewModel.navigateTo(Routes.Screen2)
                  else -> //wrong action code
               }
            }
        ) { clickHandler ->
          //Here you can put your buttons and pass in onClick the clickHandler
          Row {
                Button(onClick = { clickHandler.handleAction(0) }) {
                    Text(text = "Screen1")
                }
                Button(onClick = { clickHandler.handleAction(1) }) {
                    Text(text = "Screen2")
                }
          }
          
        }

这似乎是一个复杂的解决方案,但如果您设置了 SingleClickableComposableWrapper 和 SingleClickHandler,那么它将是可重用的。避免双击同一组件也很有帮助,这种情况很多时候都会对您的问题产生相同的效果。

© www.soinside.com 2019 - 2024. All rights reserved.