ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Compose的state

2021-08-07 11:32:29  阅读:230  来源: 互联网

标签:Compose name text onValueChange value state Modifier dp


开始:

目标是在一个text下面设置一个输入框,随着输入框变化,text也跟着变化。于是我写一个Compose function:

@Composable
fun TextAndTextField() {

    Column(modifier = Modifier.padding(16.dp)) {

        Text(
            text = "Hello",
            modifier = Modifier.padding(bottom = 6.dp),
            style = MaterialTheme.typography.h5,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
        OutlinedTextField(value = "", onValueChange = {
        }, label = {
            Text(text = "name")
        })
    }
}

 

 在框内输入任何东西都不会有反应。

 

接着:

因为我们text的内容是hard code的,我们可以试着使用一个变量来代替:

@Composable
fun TextAndTextField() {

var name = ""
Column(modifier = Modifier.padding(16.dp)) {

Text(
text = "Hello,$name",
modifier = Modifier.padding(bottom = 6.dp),
style = MaterialTheme.typography.h5,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)

OutlinedTextField(value = name, onValueChange = {
name = it

}, label = { Text(text = "name")})
}
}

但效果却和上例一样。因为可组合函数改变UI是靠重新发出(recompose)来改变的,也就是说,当state状态改变,就重新发出可组合函数的重新组合,在重新绘制UI来改变UI。但是我们的name是一个普通的变量,是不能被compose“记住的”,name改变但系统不知状态已改变, 我们需要用特殊的变量来表示一个“状态”,当这个变量改变,使得系统知道这个compose的状态改变,就重新绘制,改变UI。

 

remember上场:

 

@Composable
fun TextAndTextField() {

    val name = remember { mutableStateOf("")}
    Column(modifier = Modifier.padding(16.dp)) {

        Text(
            text = "Hello,${name.value}",
            modifier = Modifier.padding(bottom = 6.dp),
            style = MaterialTheme.typography.h5,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )
        
       OutlinedTextField(value = name.value, onValueChange = {
           name.value = it
       }, label = { Text(text = "name")})
    }

}

 

remember可以记住“{}”里面的表达式返回的值,当表达式里面的值改变时,就代表状态改变了,就通知Compose重新绘制。

note:若是旋转屏幕,状态会丢失,可以使用rememberSavable来代替remember。

 

state hoisting

一个具有高可重用性的compose function应该是stateless的,即不应该在内部包含状态。我们应该把状态提到外部去,来提升可重用性。

@Composable
fun HelloScreen() {
    val name = remember {
     mutableStateOf("")
    }
    TextAndTextField(name = name.value, onValueChange = {
        name.value = it
    })
}

@Composable
fun TextAndTextField(name: String, onValueChange: (String) -> Unit) {

    Column(modifier = Modifier.padding(16.dp)) {

        Text(
            text = "Hello,$name",
            modifier = Modifier.padding(bottom = 6.dp),
            style = MaterialTheme.typography.h5,
            maxLines = 1,
            overflow = TextOverflow.Ellipsis
        )

        OutlinedTextField(value = name, onValueChange = onValueChange, label = { Text(text = "name") })
    }

}

Compose 中的状态提升是一种将状态移至可组合项的调用方以使可组合项无状态的模式。Jetpack Compose 中的常规状态提升模式是将状态变量替换为两个参数:

  • value: T:要显示的当前值
  • onValueChange: (T) -> Unit:请求更改值的事件,其中 T 是建议的新值

不过,并不局限于 onValueChange。如果更具体的事件适合可组合项,您应使用 lambda 定义这些事件,就像使用 onExpand 和 onCollapse 定义适合 ExpandingCard 的事件一样。

 

 

使用viewmodel和observeAsState:

首先添加依赖:

implementation "androidx.compose.runtime:runtime-livedata:$compose_version"

接着看代码:

class MainActivity : ComponentActivity() {
    private val helloViewModel:HelloViewModel by viewModels()//初始化viewmodel,否则旋转屏幕无法保存状态
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            HelloScreen(helloViewModel)
        }
    }

}


class HelloViewModel : ViewModel() {
    private val _name = MutableLiveData<String>("")
    val name: LiveData<String> get() = _name

    fun onValueChanged(newName: String) {
        _name.value = newName
    }
}

@Composable
fun HelloScreen(helloViewModel: HelloViewModel = HelloViewModel()) {
    val name: String by helloViewModel.name.observeAsState("")
    val onValueChanged:(String) -> Unit = {helloViewModel.onValueChanged(it)}
TextAndTextField(name = name, onValueChange = onValueChanged) } @Composable fun TextAndTextField(name: String, onValueChange: (String) -> Unit) { Column(modifier = Modifier.padding(16.dp)) { Text( text = "Hello,$name", modifier = Modifier.padding(bottom = 6.dp), style = MaterialTheme.typography.h5, maxLines = 1, overflow = TextOverflow.Ellipsis ) OutlinedTextField( value = name, onValueChange = onValueChange, label = { Text(text = "name") }) } }

e:使用by viewModels的语法需要activity-ktx的依赖。

标签:Compose,name,text,onValueChange,value,state,Modifier,dp
来源: https://www.cnblogs.com/--here--gold--you--want/p/15111400.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有