【问题标题】:How to Maintain a Sorted List on Recomposition?如何维护重组的排序列表?
【发布时间】:2023-01-18 02:01:13
【问题描述】:

我试图找出一种方法来维护跨重组的排序列表。根据我的阅读,排序应该在 viewModel 中完成,但我的用例似乎不适合。我在我的DataTable 组件中显示一个列表。该列表最初是未排序的,但当用户单击 TableHeader 时将对其进行排序。 DataTable 用于我的 DataTableView 屏幕,它有许多状态变量,导致整个可组合项 (DataTableView) 被重新组合,因此显示原始未排序的列表。在重新组合时维护排序列表的最佳方法是什么,或者是分离可组合项但将它们放在同一屏幕上的解决方案?

数据表可组合

fun DataTable(
modifier: Modifier,
list: List<Person>
) {
// list comes from viewModel, example of data that is being passed
val list = mutableStateOf(listOf(Person("Adam", 20), Person("James", 32), Person("Ryan", 21)))

LazyColumn(
    modifier = Modifier.fillMaxSize(),
    contentPadding = PaddingValues(all = 16.dp),
    verticalArrangement = Arrangement.spacedBy(space = 16.dp)
) {
    items(
        items = list
    ) { 
      TableHeader(modifier = Modifier.clickable {
        list.value = list.value.sortedBy { it.name }
    }
  }
}

表头可组合

fun RowScope.TableHeader(
    modifier: Modifier = Modifier,
    text: String,
    sortIcon: @Composable (() -> Unit?)? = null
) {
    Row(
        modifier = modifier
            .border(.4.dp, Color.Black)
            .weight(weight)
            .padding(4.dp),
        horizontalArrangement = Arrangement.SpaceBetween
    ) {
        Text(
            text = text,
            color = MaterialTheme.colors.onPrimary
        )

        sortIcon?.let { sortIcon ->
            sortIcon()
        }
    }
}

DataTableView 可组合

fun DataTableView(viewModel: ViewModel = viewModel()) {
    var inputText: TextFieldValue by remember { mutableStateOf(TextFieldValue("")) }
    val drawerState = rememberBottomDrawerState(initialValue = BottomDrawerValue.Closed)

    DrawerBottom(
        gesturesEnabled = drawerState.isOpen,
        drawerState = drawerState,
        drawerContent = {}
    ) {
        Scaffold(
            topBar = { AppBar() },
            floatingActionButton = {
                FloatingActionButton(
                    onClick = { coroutineScope.launch { drawerState.open() } },
                    modifier = Modifier
                        .width(36.dp)
                        .height(36.dp),
                    imageVector = Icons.Filled.KeyboardArrowUp
                )
            },
            floatingActionButtonPosition = FabPosition.End,
            isFloatingActionButtonDocked = true,
        ) {
            Column {
                TextField(
                    value = inputText.text,
                    onValueChange = { newText ->
                        inputText = newText
                    },
                )
                DataTable(
                    list = viewModel.personList
                )
            }
        }
    }
}

DrawerBottom 可组合

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun DrawerBottom(
    modifier: Modifier = Modifier,
    drawerState: BottomDrawerState,
    drawerContent: @Composable ColumnScope.() -> Unit,
    drawerElevation: Dp = DrawerDefaults.Elevation,
    drawerShape: Shape = RectangleShape,
    gesturesEnabled: Boolean = false,
    drawerBackgroundColor: Color = MaterialTheme.colors.background,
    content:  @Composable () -> Unit
) {
    BottomDrawer(
        modifier = modifier,
        drawerState = drawerState,
        drawerContent = drawerContent,
        drawerElevation = drawerElevation,
        drawerShape = drawerShape,
        gesturesEnabled = gesturesEnabled,
        drawerBackgroundColor = drawerBackgroundColor,
        content = content
    )
}

我已经尝试在 viewModel 中对列表进行排序,但是当 DataTableView 重新组合时,但这意味着我需要将 viewModel 传递到我的 DataTable 可组合项中,并且根据我的理解,您希望保持 viewModels 高级别,例如,屏幕级别。

【问题讨论】:

  • “我已经尝试在 viewModel 中对列表进行排序,但是当 DataTableView 重新组合时,它仍将与传入的原始列表组合。”这就是我要推荐的内容——你知道为什么传入的是原始列表吗——原始列表不应该是list = viewModel.personList,它仍然会被排序吗?也可以试试val list = remember { mutableStateListOf&lt;Person&gt;()}val list = remember { viewModel.personLIst }之类的东西
  • @ryankuck 我错了,列表已排序,但要使用该函数对列表进行排序,我必须将 viewModel 传递到我的 DataTable 可组合项中,根据我的理解,您希望保持 viewModel 高级(屏幕级别) ), 正确的?我编辑了我的帖子以反映此评论。

标签: sorting android-jetpack-compose android-viewmodel compose-recomposition


【解决方案1】:

“remember”关键字允许您在重组过程中保留之前的值,因此您可以将其用于来自 viewModel 的列表:

fun DataTableView(viewModel: ViewModel = viewModel()) {
    ...
    // If you are getting a list that doesn't need to update from the viewModel
    val sortedListState = remember { 
         mutableStateListOf<Int>().addAll(viewModel.getSortedList())
    }


    // If you are getting Flow<List<Person>> that will update from the from the viewModel
    val sortedListStateFromFlow = remember {
        viewModel.sortedListFlow
    }.collectAsState(initial = listOf())

    DrawerBottom(
        ...
            Column {
                TextField(
                    ...
                )
                DataTable(
                    list = sortedListState
                    // OR:
                    list = sortedListStateFromFlow.value
                 )
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-25
    • 2016-05-24
    • 2012-12-09
    • 2012-05-27
    • 2012-08-11
    • 1970-01-01
    • 2019-08-17
    • 1970-01-01
    相关资源
    最近更新 更多