当二维数组中的对象中的至少一个变量发生变化时,我试图在板上实现快速图像重组。
我有一个二维数组实现为 Array<Array<Cell>>
,但是,为了实现重组,我创建了一个重复的 remember
Screen
上的变量。这工作得足够快,但它导致了应用程序业务逻辑的代码重复,并且不允许我们使用所有功能,因此这不是正确的方法。
日期类的结构Cell
:
data class Cell(
val x: Int,
val y: Int,
var isOpen: Boolean = false,
var index: Int = 0
)
Screen
代码:
val row = 5
val col = 5
val board = viewModel.board.value
Column(Modifier.verticalScroll(rememberScrollState())) {
Row(Modifier.horizontalScroll(rememberScrollState())) {
Column {
for (i in 0 until row) {
Row {
for (j in 0 until col) {
val currentItem = remember(board) { mutableStateOf(board[i][j]) } //duplicate remember variable
Image(
painter = painterResource(
id = if (currentItem.value.isOpen) {
when (currentItem.value.index) {
0 -> R.drawable.ic_num_0
1 -> R.drawable.ic_num_1
2 -> R.drawable.ic_num_3
else -> R.drawable.ic_field
}
} else {
R.drawable.ic_field
}
),
contentDescription = null,
modifier = Modifier.clickable {
currentItem.value = currentItem.value.copy(isOpen = true) // duplication of code
board[i][j].isOpen = true // from the business logic of the application
}
)
}
}
}
}
}
}
ViewModel
代码:
private val _board = mutableStateOf<Array<Array<Cell>>>(arrayOf())
val board: State<Array<Array<Cell>>> = _board
fun start() {
_board.value = createBoard()// Use case that returns Array(row) { i -> Array(col) { j -> Cell(i, j) } }
}
之后,我添加了一个重复的二维数组 Array<Array<MutableState<Cell>>>
到ViewModel
。然而,为了更新它,我必须添加两个双循环 - 一个用于转换 Array<Array<Cell>>
至Array<Array<MutableState<Cell>>>
另一个要转换Array<Array<MutableState<Cell>>>
返回Array<Array<Cell>>
。
这有助于消除 Screen
上的重复代码。并允许我们实现所有功能,但可以预见的是大大增加了点击的处理时间。
Screen
代码:
val row = 5
val col = 5
val board = viewModel.board.value
Column(Modifier.verticalScroll(rememberScrollState())) {
Row(Modifier.horizontalScroll(rememberScrollState())) {
Column {
for (i in 0 until row) {
Row {
for (j in 0 until col) {
val currentItem = remember(board) { viewModel.boardState[i][j] }
Image(
painter = painterResource(
id = if (currentItem.value.isOpen) {
when (currentItem.value.index) {
0 -> R.drawable.ic_num_0
1 -> R.drawable.ic_num_1
2 -> R.drawable.ic_num_3
else -> R.drawable.ic_field
}
} else {
R.drawable.ic_field
}
),
contentDescription = null,
modifier = Modifier.combinedClickable(
onClick = {
viewModel.updateBoard(
board[i][j],
Event.OnClick
)
}
)
)
}
}
}
}
}
}
ViewModel
代码:
fun updateBoard(cell: Cell? = null, event: Event? = null) {
val newBoard = boardState.map { row -> row.map { item -> item.value }.toTypedArray() }.toTypedArray() // one double loops
_board.value = updateBoard(newBoard, cell, event) // Use case that returns Array(row) { i -> Array(col) { j -> Cell(i, j) } }
boardState = board.value.map { row -> row.map { item -> mutableStateOf(item) }.toTypedArray() }.toTypedArray() // two double loops
}
问题:在更改二维数组中任何对象的变量时如何实现快速重组?
注意:在我的项目中,我遵循整洁架构的原则,所以我不能使用 Array<Array<MutableState<Cell>>>
在域级别,因为 MutableState
是 androidx
的一部分图书馆。
此外,我想补充一点,当您单击二维字段单元格时,其他单元格可能会发生变化,而不仅仅是被单击的单元格。
也许可以使用 MutableStateFlow
来解决这个问题然而,与 MutableState
不同,它不会导致元素被重组。也许还有其他我不知道的方法。
更新:我尝试转换 Array<Array<Cell>>
至Array<Array<MutableStateFlow<Cell>>>
,并转换StateFlow
撰写State
在Screen
使用collectAsState()
,但这会导致错误。
Screen
:
val board by viewModel.board
Column(Modifier.verticalScroll(rememberScrollState())) {
Row(Modifier.horizontalScroll(rememberScrollState())) {
Column {
for (i in 0 until row) {
Row {
for (j in 0 until col) {
val currentItem = remember(board) { board[i][j].collectAsState() } // error
...
ViewModel
:
private val _board = mutableStateOf<Array<Array<MutableStateFlow<Cell>>>>(arrayOf())
val board: State<Array<Array<MutableStateFlow<Cell>>>> = _board
fun updateBoard(cell: Cell? = null, event:Event? = null) {
_board.value = updateBoard(board.value, cell, event)
}
最佳答案
当您读取状态时会发生重组。所以我认为最整洁的方法是为每个单元格使用可变状态列表,并且只在单元格中读取。请注意,如果您内联 Cell
,它会导致整个集合重组,因为 Row
和 Column
是内联函数,会阻止 Compose 进行智能重组。
@Composable
fun Test() {
val m = 10
val n = 10
val state = remember {
List(m) {
List(n) { mutableStateOf(0) }
}
}
val coroutineScope = rememberCoroutineScope()
Column {
for (i in 0 until m)
Row {
for (j in 0 until n)
Cell(
state = state[i][j],
onClick = {
state[i][j].value += 1
},
)
}
}
}
@Composable
private fun Cell(
state: State<Int>,
onClick: () -> Unit,
) {
Text(
state.value.toString(),
modifier = Modifier
.clickable(onClick = onClick)
.padding(10.dp)
)
}
如果由于某种原因您需要在数据层上执行此操作,并且出于某些架构原因想要使用不可变状态,您可以对流使用相同的方法 - 您只需要有一个可以单独为每个值收集它的点。
@Composable
fun Test() {
val m = 10
val n = 10
val state = remember {
MutableStateFlow(
List(m) {
List(n) { 0 }
}
)
}
val coroutineScope = rememberCoroutineScope()
Column {
for (i in 0 until m)
Row {
for (j in 0 until n)
Cell(
valueStateFlow = remember {
state.map { it[i][j] }.stateIn(coroutineScope, SharingStarted.Eagerly, state.value[i][j])
},
onClick = {
state.value = state.value.toMutableList().also {column->
column[i] = column[i].toMutableList().also { row ->
row[j] = row[j] + 1
}.toImmutableList()
}.toImmutableList()
},
)
}
}
}
@Composable
private fun Cell(
valueStateFlow: StateFlow<Int>,
onClick: () -> Unit,
) {
val value by valueStateFlow.collectAsState()
Text(
value.toString(),
modifier = Modifier
.clickable(onClick = onClick)
.padding(10.dp)
)
}
关于android - 当 2d 数组元素的变量在 Compose with Clean Architecture 中发生变化时重新组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76177971/