如何从 viewModel 和其他可组合项更改 TextField 值?

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

这里是 MainViewModel.kt:

class MainViewModel : ViewModel() {

    var fruit by mutableStateOf("") // changed only by changeFruit() method
        private set

    /** Validates and changes [fruit] and returns the result. */
    fun changeFruit(value: String): String {
        fruit = if (value == "apple") "banana" else value
        return fruit
    }

    // ...other methods that can change the fruit variable with changeFruit()...
}

这里是 MainActivity.kt:

import ...

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Tests5Theme {
                App()
            }
        }
    }
}

@Composable
fun App() {
    val vm: MainViewModel = viewModel()

    Column {
        var fieldValue by remember { mutableStateOf(vm.fruit) }
        
        Field(
            value = fieldValue,
            onValueChange = { fieldValue = it },
            onDone = { vm.changeFruit(fieldValue) }
        )

        // I know onClick could be { fieldValue = vm.changeFruit("apple") }
        // and { fieldValue = vm.changeFruit("strawberry") }
        // but what if these buttons are placed away in other composables?

        Button(onClick = { vm.changeFruit("apple") }) {
            Text(text = "Change fruit to apple")
        }
        Button(onClick = { vm.changeFruit("strawberry") }) {
            Text(text = "Change fruit to strawberry")

        }
        Text(text = "Value of MainViewModel.fruit: ${vm.fruit}")
    }
}

/**
 * When the done button of the keyboard is pressed, the focus is cleared from the field, then the onFocusChanged()
 * modifier is called, and then onDone() is called.
 *
 * @param value the value shown in the field.
 * @param onValueChange the lambda called when the field value is changed.
 * @param onDone the lambda called when the done button of the keyboard is pressed or the focus goes away.
 */
@Composable
fun Field(
    value: String,
    onValueChange: (String) -> Unit,
    onDone: () -> Unit
) {
    val focusManager = LocalFocusManager.current
    TextField(
        value = value,
        onValueChange = onValueChange,
        modifier = Modifier.onFocusChanged {
            if (!it.isFocused) onDone()
        },
        keyboardActions = KeyboardActions(
            onDone = { focusManager.clearFocus() }
        ),
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done),
    )
}

fruit
的值可以在文本字段中键入、按下按钮或使用 Viewmodel 中的其他方法进行更改。在调用
fieldValue
函数后,我无法弄清楚如何使
fruit
(textField的值)等于
changeFruit()
变量。

在此先感谢帮助我的人。

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

fruit
已经是保存在
viewModel
中的状态,这里的问题是您正在使用
remember
初始化另一个状态。请记住,通过组合生命周期保存值,因此当在
fieldValue
lambda 中设置
onValueChange = { fieldValue = it }
时,您的视图会更新,因为设置状态会触发重新组合,但是当您以编程方式设置它时它不会更新,因为没有任何东西可以触发重新组合.有两种解决方案:

1.你可以直接使用

viewModel
中的状态,不要用remember创建另一个冗余状态。

@Composable
fun App() {
    val vm: MainViewModel = viewModel()

    Column {
        Field(
            value = vm.fruit,
            onValueChange = { vm.changeFruit(it) }
        )
    }
}

2.将

key
传递给
remember
会强制它重新计算它存储的值,这也会触发重组

@Composable
fun App() {
    val vm: MainViewModel = viewModel()
    var fieldValue by remember(key1 = vm.fruit) { mutableStateOf(vm.fruit) }

    Column {
        Field(
            value = fieldValue,
            onValueChange = { vm.changeFruit(it) }
        )
    }
}

有关性能的附加信息,将

value
直接传递给您的 Composable 将导致整个父 Composable 中的重组,在您的情况下为
App()
,因为重组将在其范围内有 state read 时开始,这意味着如果其他可组合项不是
skippable
.

,则对它们进行冗余重组
@Composable
fun Field(
    provideValue: () -> String,
    onValueChange: (String) -> Unit
) {
    TextField(
        value = provideValue(),
        onValueChange = onValueChange
    )
}

@Composable
fun App() {
    Field(
        provideValue = { vm.fruit },
        onValueChange = { vm.changeFruit(it) }
    )
}

这种状态将在

provideValue()
lambda 的范围内读取,而 不在父可组合项 中,因此重组只会发生在
Field()
可组合项中。这称为 lambda 方法,建议使用它来传递频繁变化的状态。

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