iOS. Support different `onFocusBehavior` for different screens in one `ComposeUIViewController`
Compose 1.5.0 introduces a new feature that allows to configure onFocusBehavior for text fields:
fun MainViewController() = ComposeUIViewController(configure = {
onFocusBehavior = OnFocusBehavior.None
}) {
App()
}
This useful if the app uses different ViewController's for different screens, but not useful, when the app is written in a single view controller, where different screens can require different behaviors. This will probably be the recommended approach in the future (it is not decided yet, but it is the recomended approach in Android).
- Figure out how Compose on Android solves the different behavior of keyboard in a single activity case.
- Does Compose for Android has a specific API, or users should use native API (
window.setSoftInputMode) to dynamically change the behavior. - Decide if a solution of supporting dynamic changes of
onFocusBehaviorwill be enough (make itmutableStateOf), or we should introduce local declarative API (TextField(onFocusBehavior=)).
https://github.com/JetBrains/compose-multiplatform/assets/3532155/1644eca2-c977-4d32-85c6-584ca14f0736
I investigated the problem.
I guess we don't have to change the current behavior.
onFocusBehavior flag is similar to Android's windowSoftInputMode.
The requested feature (different behaviors for different Text fields on the same screen) can be achieved by setting a focus listener and an insets handler:
@Composable
internal fun App() = AppTheme {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.BottomCenter
) {
val initialBottomPadding = 100.dp
var f1IsFocused by remember { mutableStateOf(false) }
var f1 by remember { mutableStateOf("") }
OutlinedTextField(
value = f1,
onValueChange = { f1 = it },
label = { Text("Movable TextField") },
singleLine = true,
modifier = Modifier
.fillMaxWidth()
.padding(start = 16.dp, end = 16.dp, bottom = initialBottomPadding)
.onFocusChanged { f1IsFocused = it.isFocused }
.let {
if (f1IsFocused) {
it.padding(bottom = max(0.dp, WindowInsets.ime.asPaddingValues().calculateBottomPadding() - initialBottomPadding))
} else {
it.padding(bottom = 0.dp)
}
}
)
var f2 by remember { mutableStateOf("") }
OutlinedTextField(
value = f2,
onValueChange = { f2 = it },
label = { Text("Stable TextField") },
singleLine = true,
modifier = Modifier.fillMaxWidth().padding(16.dp)
)
}
}
The requested feature (different behaviors for different Text fields on the same screen)
onFocusBehavior offsets/resizes the whole screen, not the component. This allows to show a proper scrolling, if we try to scroll with keyboard shown.
But it seems that indeed, users can implement something on the root level themselves.
But for that we need to either disable the default offseting (which isn't good) or provide an option to disable it. We done that we already done via onFocusBehavior.
The only issue I see now, that users have to write its own logic instead of using built-in one. It adds some code, and can differ.
If we don't have any more ideas what can be improved here, let's close it then until we have real cases?
onFocusBehavior flag is similar to Android's windowSoftInputMode.
It can be changed dynamically compared to the confiugure approach that is called only on init
Do you mean getWindow().setSoftInputMode(...)?
Yes
Is it possible to call from a compose code or you propose to add such an api to common compose?
Is it possible to call from a compose code
Yes, users can pass Activity/Window in their Composables. But it is not a Compose API.
So, we have a situation that Android platform has a feature "change input mode dynamically", Compose doesn't have it, and user might need it.
We have options:
- [easy] wait for a real user request
- [normal] introduce ios-only API for entry-point properties changing. For example, we can make
configurereact tomutableStateOf, asUIKitView(update=does that. - [hard] introduce platform-independent Compose API (needs coordination with Google)
I would choose the first or the second.
I guess it is not a popular API for compose apps. But I may be wrong. Let's wait for the user requests 👌
Let's wait for the user requests 👌
Let's keep this issue open then.
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.