https://kotlinlang.org logo
#compose
Title
# compose
l

Lukasz Kalnik

02/17/2022, 3:42 PM
I want a
TextField
with prefilled text to set the cursor at the end of the text when it gains focus using
LaunchedEffect { focusRequester.requestFocus() }
. I store the text string itself in a ViewModel, but I don't want to keep the whole
TextFieldValue
(including cursor position) inside the ViewModel. It seems that the
TextField
should be able to take care of its cursor position on its own. Is there a way to do it?
Is a hybrid approach possible using
remember
inside the composable to store the
TextFieldValue
and storing the text string itself outside the composable, in ViewModel?
I'm trying right now to just store the text string (the
uiState.name
variable) like this:
Copy code
@Composable
fun EnterNameDialog(
    uiState: EnterNameDialogState,
) {
    val currentText = remember(uiState.name) { mutableStateOf(uiState.name) }
    AlertDialog(
                text = {
                        OutlinedTextField(
                            value = currentText.value,
                            onValueChange = { currentText.value = it },
                            // ...
}
But the problem is that after a recomposition the initial
uiState.name
gets restored (because it's remembered). How can I update
currentText.value
so that it doesn't get overwritten after a recomposition? What's the point of having write access to a
MutableState
if it gets forgotten after a recomposition? Is there a way to "reinitialize"
remember
? Or should I not use
remember
at all?
z

Zoltan Demant

02/17/2022, 3:56 PM
I think the issue is that youre specifying
remember(uiState.name)
which results in a new mutableState being created everytime the name changes. If you just do remember without any argument, it will retain the value for as long as the composable is active, and I think thats what you want.
l

Lukasz Kalnik

02/17/2022, 3:59 PM
No, that's intentional. I want to be able to update the name from my viewmodel
The problem is actually that
currentText.value
gets forgotten as soon as recomposition happens
I mean precisely this:
Copy code
onValueChange = { currentText.value = it }
This updates the text as long as I type. The moment I e.g. change the device configuration and the recomposition happens, the old remembered state (with the
uiState.name
initially set from the ViewModel) gets restored.
So somehow
remember
ignores the last changes to the
MutableState
And I am not able to use
MutableState
without
remember
z

Zoltan Demant

02/17/2022, 4:06 PM
Perhaps it would be worth looking into
rememberSaveable
, that should persist the value across orientation changes, etc; just using remember will result in the value being recreated, since the scope of the composable is recreated when the device is rotated.
l

Lukasz Kalnik

02/17/2022, 4:07 PM
Yes Thanks so much, this is just what I needed!
It works now 😄
👍🏽 1
It was really not clear to me that
remember
doesn't survive configuration change...
I thought it's like any other recomposition.
mind blown 1
c

Colton Idle

02/17/2022, 5:26 PM
In a pure compose app you can turn off most configuration changes and it saves you from having to do rememberSaveable in a lot of cases. things like wallpaper changing could still cause a config change tho and you cant opt out of that
🙏 1
l

lesincs

02/18/2022, 3:32 AM
Hi, is there any references for this theory? I've heard people talking about pure compose app and configure changes things a lot, but got confused of the difference between a view based app and pure compose pertaining to the configure changes.
c

Colton Idle

02/18/2022, 5:31 AM
You can search in the compose channel from Adam Powell (compose tech lead and overall awesome android dev thats been on the g team since the early days) and search for configChanges. He talks through it
❤️ 1
l

Lukasz Kalnik

02/18/2022, 8:57 AM
I think this is one of the good threads on this topic: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1618691113058800
👍 1
a

Arun Joseph

02/23/2022, 8:46 PM
Looking at the original problem, will it be solved if
onValueChanged
send
it
to the view model and letting view model update
uiState.name
? I have similar case and i do this .
l

Lukasz Kalnik

02/24/2022, 8:53 AM
Yes, this is the simple solution - keep all the state only in viewmodel. However we wanted to have kind of a hybrid architecture. The state should be kept inside the composable (using
remember
) to set the cursor position at the end of the text when the dialog is open. There is no other way to set cursor position in
TextField
. And I don't want to keep the whole
TextFieldValue
including the cursor position inside the ViewModel. ViewModel should not know anything about the cursor position, unless there is some really custom logic based on this.
@Arun Joseph to change the cursor position it's not enough to store the
uiState.name
in ViewModel. You need another
TextField
method overload which takes
TextFieldValue
as
value
(instead of
String
).
TextFieldValue
also contains the cursor position.
a

Arun Joseph

02/24/2022, 8:58 AM
Ok, I understood, its a TextField thing and makes sense to be handled in Composable.
👍 1
3 Views