查看Immutable 的文档,有一个代码示例:
@Immutable
data class Person(val name: String, val phoneNumber: String)
@Composable
fun PersonView(person: Person) {
Column {
Row {
Text("Name: ")
Text(person.name)
}
Row {
Text("Phone: ")
Text(person.phoneNumber)
}
}
}
@Composable
fun PeopleView(people: List<Person>) {
Column {
for (person in people) {
PersonView(person)
}
}
}
Run Code Online (Sandbox Code Playgroud)
和标题:
如果将 Person 标记为不可变,则如果与上次合成期间是同一个人,则可以跳过调用 PersonView Composable 函数。
我的问题是:
如果重组仅在函数参数@Composable更改时发生,并且像上面的代码中那样的数据类Person(即仅包含原始值)不能在不创建新实例的情况下更改,那么这里的优化是什么?与没有注释
的相同代码相比,什么时候会跳过对 PersonView Composable 函数的调用?它是否与 的可变/不稳定参数有关?@Immutablepeople: List<Person>PeopleView
I have a text which need to be animated to show and hide with the value is null or not. it would have been straight forward if the visibility is separately handle, but this is what I got. In the bellow code the enter animation works but the exit animation dont as the text value is null. I can think of something with remembering the old value but not sure how.
@Composable
fun ShowAnimatedText(
text : String?
) {
Column( …Run Code Online (Sandbox Code Playgroud) android android-jetpack-compose jetpack-compose-animation compose-recomposition
如何创建这样的弧形进度条动画
目前我已经使用 Canvas 绘制圆弧并使用 animateFloatAsState API 将动画添加到进度条。但第二张照片不是我的预期。
[
]
// e.g. oldScore = 100f newScore = 350f
// Suppose 250 points are into one level
@Composable
fun ArcProgressbar(
modifier: Modifier = Modifier,
oldScore: Float,
newScore: Float,
level: String,
startAngle: Float = 120f,
limitAngle: Float = 300f,
thickness: Dp = 8.dp
) {
var value by remember { mutableStateOf(oldScore) }
val sweepAngle = animateFloatAsState(
targetValue = (value / 250) * limitAngle, // convert the value to angle
animationSpec = tween(
durationMillis …Run Code Online (Sandbox Code Playgroud) android android-progressbar android-jetpack-compose jetpack-compose-animation compose-recomposition
我从开发者网站上关注了这份文档。我想显示用户输入中的文本OutlinedTextField,并使其在配置更改后保持不变。
使用下面的代码,当用户从键盘输入文本时,OutlinedTextField不会更新文本。
HelloContent(name = city.name, onNameChange = { city.name = it})//Doesn't work
Run Code Online (Sandbox Code Playgroud)
然而这行代码可以正常工作:
HelloContent(name = temp, onNameChange = { temp = it})//Work
Run Code Online (Sandbox Code Playgroud)
下面是我用来实现的代码:
@Composable
fun HelloScreen() {
var city by rememberSaveable(stateSaver = CitySaver) {
mutableStateOf(City("Hanoi","VietNam"))
}
var temp by rememberSaveable {
mutableStateOf("")
}
Column {
HelloContent(name = city.name, onNameChange = { city.name = it})//Doesn't work
HelloContent(name = temp, onNameChange = { temp = it})//Work
}
}
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose compose-recomposition mutablestateof
我正在从服务器获取数据并将其显示在列表中,可以一键选择每个项目以显示按钮,但我无法关闭它,只能打开它。
这是列表类的项目
data class Task(
val deviceName: String,
val deviceId: String,
var selected :Boolean= Boolean,
)
Run Code Online (Sandbox Code Playgroud)
这是数据类
data class TaskStatus(
val taskList: SnapshotStateList<Task> = SnapshotStateList(),
val selectedNumber: Int = -1,
)
Run Code Online (Sandbox Code Playgroud)
我的ViewModel
private val _status = MutableStateFlow(TaskStatus())
val status = _status.asStateFlow()
fun getList(){
...
for(item in result){
_status.value.taskList.add(task)
}
}
fun selectTask(task: Task) {
val list = _status.value.taskList
val selectNumber = _status.value.selectedNumber
val newSelectNumber = list.indexOf(task)
if (newSelectNumber != selectNumber) {
if (selectNumber != -1) {
list[selectNumber].selected.value = false …Run Code Online (Sandbox Code Playgroud) android kotlin android-jetpack-compose lazycolumn compose-recomposition
想象一下下面的物体
data class CourseState(
val key:Int=0,
val name:String="",
val courses:Courses=Courses())
Run Code Online (Sandbox Code Playgroud)
实现以下模式
private val _courseState = mutableStateOf(CourseState())
val courseState: State<CourseState> = _courseState
Run Code Online (Sandbox Code Playgroud)
我可以通过调用以下命令来触发 UI 的重构:
_courseState.value = CourseState()
Run Code Online (Sandbox Code Playgroud)
但不是通过调用:
_courseState.value.courses.addCourse(Course("some course))
Run Code Online (Sandbox Code Playgroud)
这有点令人沮丧,因为即使该对象明显发生了变化,我也被迫创建父对象的一个全新实例,以便引发其中的微小变化。
现在,我知道 Compose 在幕后使用该.equals()方法来确定是否应该重新组合布局,因此我对如何实现所需的行为有了一些想法。
覆盖该equals方法:这将意味着一些样板代码,并且必须对构成我的对象的整个嵌套类集完成。这可能有效,但看起来危险且麻烦。
使用clone接受其自己类的实例作为参数的方法或构造函数来创建对象的相同副本,该副本仍然代表我可以修改的新实例,然后作为可变状态值传递。听起来比之前的选择更容易,但优雅是不同的
深入研究 State 和 MutableState 类,看看是否有办法让它们按照我想要的方式运行。我依赖你们中的一些人以前做过这件事,所以我不必 XD
让我知道你的想法,或者是否有其他一些明显的解决方案到目前为止我还没有想到
android kotlin android-jetpack-compose compose-recomposition
我有一个LazyColumn嵌套的LazyRows(类似于 Netflix 或 Spotify 主页提要)。简而言之,我遇到的问题是,当页面内容更改时,嵌套 LazyRows 的滚动位置不会重置。
例如,用户向下滚动主页,滚动第三个水平部分看到第五项,刷新主页,加载新的页面内容。但第三个水平部分仍然显示第五个而不是重置到初始位置。
在代码方面,这里有一些片段:
在主屏幕可组合项中:
Scaffold {
when (val viewState = viewModel.stateFlow.collectAsState().value) {
is ViewState.Success -> {
Box {
with(viewState.data) {
LazyColumn {
itemsIndexed(sections) { index, section ->
LazyRow{}
//etc.
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在 HomeViewModel 中,当用户刷新主屏幕时,调用此函数:
private val _stateFlow = MutableStateFlow<ViewState<HomePage>>(ViewState.Loading)
val stateFlow: StateFlow<ViewState<HomePage>>
get() = _stateFlow
fun loadHomeScreen() {
viewModelScope.launch {
repository.getHomePage()
.collect {
_stateFlow.tryEmit(it)
}
}
}
Run Code Online (Sandbox Code Playgroud)
现在,我已成功添加额外的代码,以便在用户刷新主屏幕时将主页的 LazyColumn 滚动到屏幕顶部。但是,我仍然不知道对于嵌套 LazyRows 来说最好的方法是什么。我不想保留对他们的引用,LazyListState因为该解决方案无法很好地扩展。但是,我很困惑为什么在发出新状态并显示新的 LazyRows 时滚动位置没有被重置。这是 Compose …
android kotlin android-jetpack-compose lazycolumn compose-recomposition
这是一个视频通话屏幕。它需要令牌和通道名称才能工作,需要将其传递给初始化调用引擎。我将它们存储在用作可变状态的数据类中。
屏幕状态数据类
@Keep
data class CallScreenState(
val callerId: Int? = null,
val recieverId: Int? = null,
val chatRoom: ChatRoom.Data? = null,
val rtcToken: AgoraTokenResponse.TokenData? = null
)
Run Code Online (Sandbox Code Playgroud)
并在视图模型初始化状态下通过以下代码:
var callScreenState by mutableStateOf(CallScreenState())
Run Code Online (Sandbox Code Playgroud)
在聊天室和令牌 api 成功响应的视图模型中,状态将使用此代码进行更新。
callScreenState = callScreenState.copy(
chatRoom = chatRoom.data,//from response
rtcToken = token.data //from response
)
Run Code Online (Sandbox Code Playgroud)
从这里开始,预计将使用 chatRoom 和 rtcToken 的新更新值重新组合屏幕。
并且在可组合中
val screenState = remember {
viewModel.callScreenState
}
Run Code Online (Sandbox Code Playgroud)
此屏幕状态用于将值传递给 init 引擎
val mEngine = remember {
initEngine(
context,
object : IRtcEngineEventHandler() {
override fun onJoinChannelSuccess(channel: String?, uid: …Run Code Online (Sandbox Code Playgroud) android kotlin kotlin-coroutines android-jetpack-compose compose-recomposition
考虑下面的片段
fun doSomething(){
}
@Composable
fun A() {
Column() {
val counter = remember { mutableStateOf(0) }
B {
doSomething()
}
Button(onClick = { counter.value += 1 }) {
Text("Click me 2")
}
Text(text = "count: ${counter.value}")
}
}
@Composable
fun B(onClick: () -> Unit) {
Button(onClick = onClick) {
Text("click me")
}
}
Run Code Online (Sandbox Code Playgroud)
现在,当按下“click me 2”按钮时,B compose 函数将被重新组合,尽管其中的任何内容都没有改变。
澄清: doSomething 用于演示目的。如果您坚持要一个实际的例子,您可以考虑以下 B 的用法:
B{
coroutinScope.launch{
bottomSheetState.collapse()
doSomething()
}
}
Run Code Online (Sandbox Code Playgroud)
从 compose 编译器报告中我可以看到 B …
Jetpack compose 文档表示,如果所有输入稳定且未更改,它可以跳过重组。稳定类型的定义是这样的......
稳定类型必须遵守以下合同:
- 对于相同的两个实例,两个实例的 equals 结果将永远相同。
- 如果该类型的公共属性发生变化,Composition 将会收到通知。
- 所有公共财产类型也都很稳定。
我无法清楚地理解这一点。有人可以向我解释一下 compose 如何检查类型是否稳定吗?我可以理解如果 compose 确定类型是稳定的,那么它将使用 equals 方法检查是否相等。但是如何说一个类是否稳定,以便我们能够尽可能地理解和支持智能重组呢?
我试着玩了一下,发现了以下内容。
This data class Student is not stable, even if I pass the same instance again, its recomposing
data class Student(
var id:Int=1,
var name:String="Anonymous")
Run Code Online (Sandbox Code Playgroud)
然而,当我们再次传递相同的实例时,以下类被视为稳定的并且有利于智能重组
This class is stable when all the public parameters are changed to val
data class Student(
val id:Int=1,
val name:String="Anonymous")
Run Code Online (Sandbox Code Playgroud)
所以,我可以理解所有公共属性都应该是不可变的。但令我困惑的是,下面的类也被视为稳定的并且支持智能重组。为什么?
This MainActivityVM class is considered Stable when passing like
@Composable
fun StudentList(viewModel:MainActivityVM){
...
}
class MainActivityVM …Run Code Online (Sandbox Code Playgroud)