Reputation: 139
In my @Composable function, whenever a focusable component is added, pressing the remote back button does not trigger the BackHandler event. At that time, the focusable component clears its focus, and only after pressing the back button again does the BackHandler event get triggered.
I want the BackHandler event to trigger every time, regardless of whether a focusable item is present or not.
Here’s my code:
App.kt
@Composable
fun App() {
val navController = rememberNavController()
val context = LocalContext.current
NavHost(navController = navController, startDestination = Splash) {
composable<Splash> {
SplashScreen {
navController.navigate(MainContent) {
popUpTo(Splash) { inclusive = true }
}
}
}
composable<Download> {
DownloadScreen {
navController.navigate(MainContent) {
popUpTo(Download) { inclusive = true }
}
}
}
composable<MainContent> {
MainContentScreen(onBackClick = {
(context as? ComponentActivity)?.finish()
})
}
}
}
MainContentScreen.kt
@Composable
fun MainContentScreen(onBackClick: () -> Unit) {
val focusRequester = remember { FocusRequester() }
val isSettingOpen = remember { mutableStateOf(false) }
BackHandler {
Log.e("TAG", "MainContentScreen: BackHandler")
if (isSettingOpen.value) {
isSettingOpen.value = false
} else {
onBackClick()
}
}
Box(
modifier = Modifier
.fillMaxSize()
.focusRequester(focusRequester = focusRequester)
.onDpadCenterClick {
Log.e("TAG", "MainContentScreen: onDpadCenterClick")
isSettingOpen.value = true
}, contentAlignment = Alignment.Center
) {
Text("MainContent Screen")
}
if (isSettingOpen.value) {
SettingsScreen(onBackClick = {
isSettingOpen.value = false
})
}
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
Extension Fun for Dpad center click
fun Modifier.onDpadCenterClick(onDpadCenterClick: () -> Unit): Modifier {
return this.then(Modifier
.focusable()
.onKeyEvent { keyEvent ->
if (keyEvent.nativeKeyEvent.action == KeyEvent.ACTION_UP) {
when (keyEvent.nativeKeyEvent.keyCode) {
KeyEvent.KEYCODE_DPAD_CENTER -> {
onDpadCenterClick()
true // Consume the event
}
else -> false
}
} else {
false
}
})
}
SettingsScreen.kt
@Composable
fun SettingsScreen(onBackClick: () -> Unit) {
val focusRequester = remember { FocusRequester() }
BackHandler {
Log.e("TAG", "SettingsScreen: BackHandler Called Close")
onBackClick()
}
Box(
modifier = Modifier
.fillMaxSize()
.background(color = SettingsBG)
.focusable()
.focusRequester(focusRequester = focusRequester)
) {
Column {
MPButton(text = "Text 1") {
Log.e("TAG", "SettingsScreen: text 1 click")
}
MPButton(text = "Text 2") {
Log.e("TAG", "SettingsScreen: text 2 click")
}
}
}
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
MPButton.kt
@Composable
fun MPButton(text: String, onClick: () -> Unit) {
Card(
modifier = Modifier.padding(all = 10.dp), onClick = onClick
) {
Text(text = text)
}
}
In my case On the MainContentScreen, when the D-pad center button is clicked, it should open the SettingsScreen. Inside the SettingsScreen, there are two MPButtons labeled text1 and text2, with the focus initially on text1. I want to handle the BackHandler event based on whether text1 or text2 is focused or not.
Upvotes: 4
Views: 64
Reputation: 139
After research and trial and error, I discovered that I simply needed to remove Modifier.focusable() from the Box modifier.
Updated code... SettingsScreen.kt
@Composable
fun SettingsScreen(onBackClick: () -> Unit) {
val focusRequester = remember { FocusRequester() }
BackHandler {
Log.e("TAG", "SettingsScreen: BackHandler Called Close")
onBackClick()
}
Box(
modifier = Modifier
.fillMaxSize()
.background(color = SettingsBG)
.focusRequester(focusRequester = focusRequester)
) {
Column {
MPButton(text = "Text 1") {
Log.e("TAG", "SettingsScreen: text 1 click")
}
MPButton(text = "Text 2") {
Log.e("TAG", "SettingsScreen: text 2 click")
}
}
}
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
Let me know if you need any help with Jetpack Compose. We need to build a large community for Jetpack Compose.
Upvotes: 0