Вот экран :

При работе с фокусом есть две основные задачи:
- При навигации слева направо и наоборот фокус не должен путать позиции . Например, если пользователь щелкнет вправо от левой панели 0 -> Правая панель 0, затем перейдет к правой панели 2, а затем щелкнет влево, фокус должен вернуться на левую панель 0. потому что пользователь переместил фокус с левой панели на правую. Эта функциональность была реализована с помощью focusRestorer и уже работает.
- Когда пользователь нажимает на элемент на правой панели (например, , Правая панель 1), откроется второй экран. Когда пользователь нажимает кнопку «Назад» и возвращается к первому экрану, ожидается, что фокус будет на кнопке, открывшей экран, то есть на правой панели 1. Однако по какой-то причине это работает только в 30 % случаев, и вместо фокусировки на ожидаемой кнопке фокусируется другая кнопка.
Есть готовый код:
Код: Выделить всё
private const val FIRST_SCREEN_ROUTE = "first_screen"
private const val SECOND_SCREEN_ROUTE = "second_screen"
private const val DEFAULT_FOCUS_POSITION = -1
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
Test_delete_itTheme {
Surface(
modifier = Modifier.fillMaxSize(),
shape = RectangleShape
) {
Greeting()
}
}
}
}
}
@Composable
fun Greeting() {
val navigator: NavHostController = rememberNavController()
NavHost(
navController = navigator,
startDestination = FIRST_SCREEN_ROUTE
) {
composable(FIRST_SCREEN_ROUTE) {
DisposableEffect(Unit) {
Log.e("HERE", "1 CREATED first_screen_route")
onDispose {
Log.e("HERE", "DISPOSED first_screen_route")
}
}
FirstScreen(onClick = {
Log.e("HERE", "NAVIGATION TO SECOND SCREEN")
navigator.navigate(SECOND_SCREEN_ROUTE)
})
}
composable(SECOND_SCREEN_ROUTE) {
DisposableEffect(Unit) {
Log.e("HERE", "CREATED second_screen_route")
onDispose {
Log.e("HERE", "DISPOSED second_screen_route")
}
}
SecondScreen()
}
}
}
@Composable
fun SecondScreen() {
Box(
modifier = Modifier
.fillMaxSize()
.background(Color.Red.copy(alpha = 0.1f)),
contentAlignment = Alignment.Center
) {
Text(text = "SECOND SCREEN")
}
}
@Composable
fun FirstScreen(
onClick: () -> Unit
) {
var focusBtnIdx by rememberSaveable { mutableIntStateOf(DEFAULT_FOCUS_POSITION) }
Row(modifier = Modifier
.fillMaxSize()
) {
LeftPanel()
RightPanel(onClick = onClick, focusBtnIdx = focusBtnIdx, setFocusBtnIdx = { focusBtnIdx = it })
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun RowScope.LeftPanel() {
val firstItemFr = remember { FocusRequester() }
val buttons by rememberSaveable { mutableStateOf(List(5) { "Button ${it + 1}" }) }
LaunchedEffect(Unit) {
this.coroutineContext.job.invokeOnCompletion {
try { firstItemFr.requestFocus() }
catch (e: Exception) {/* do nothing */ }
}
}
TvLazyColumn(
modifier = Modifier
.focusRestorer { firstItemFr }
.background(Color.Blue.copy(alpha = 0.1f))
.fillMaxHeight()
.weight(1f),
verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
itemsIndexed(
items = buttons,
key = { idx, _ -> idx }
) { idx, _ ->
Button(
modifier = Modifier
.let { modifier ->
if (idx == 0) {
modifier.focusRequester(firstItemFr)
} else {
modifier
}
},
onClick = {}
) {
Text(text = "Left Panel: $idx")
}
}
}
}
@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun RowScope.RightPanel(
onClick: () -> Unit,
focusBtnIdx: Int,
setFocusBtnIdx: (Int) -> Unit
) {
val firstItemFr = remember { FocusRequester() }
LaunchedEffect(Unit) {
this.coroutineContext.job.invokeOnCompletion {
try {
Log.e("HERE", ">>> REQUEST FOCUS")
if (focusBtnIdx != DEFAULT_FOCUS_POSITION) {
firstItemFr.requestFocus()
Log.e("HERE", "
Подробнее здесь: [url]https://stackoverflow.com/questions/78708685/how-to-assign-focus-to-the-same-position-when-returning-to-the-screen[/url]