我正在将应用程序从 View 迁移到 Compose。该应用程序是用 Java 编写的,因此我需要将 UI 迁移到 Kotlin。 我更喜欢尽可能逐步地进行,因此我将 ViewModel 保留在 Java 中。
UI 是卡片的惰性列。长按卡片可切换其“已选择”状态。它将一个事件发送到 ViewModel - 在包含所选卡片 ID 的列表中添加/删除其 ID。 我希望 UI 能够观察 ID 列表中的变化。 目前,我使用一种解决方法:一个可观察的布尔值,它会随着 ID 列表中的每次更改而切换。我想知道是否有更好的方法。
一些代码: UI部分-显示卡片的功能:
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun DisplayAlarmItem(alarmItem: AlarmItem) {
// Force this function to be called when list of selected changes
val selectToggle by parent!!.alarmViewModel.selectToggleObserve.observeAsState( )
val toggled = if (selectToggle!=null && selectToggle as Boolean) "A" else "B"
// Get list of selected alarms and mark this item as selected(yes/no)
val selectedAlarmList by parent!!.alarmViewModel.selectedItems.observeAsState()
val filterList = selectedAlarmList?.filter { it.equals(alarmItem.createTime.toInt()) }
var selected= (filterList != null && filterList.isNotEmpty())
val backgroundColor = if (selected) MaterialTheme.colorScheme.surfaceVariant else MaterialTheme.colorScheme.surface
val currentAlpha = if (alarmItem.isActive) 1.0f else 0.3f
Card(
modifier = Modifier
.padding(5.dp)
.fillMaxWidth()
.combinedClickable(
onLongClick = { AlarmItemLongClicked(alarmItem.getCreateTime()) },
onClickLabel = "Edit Alarm"
)
{ AlarmItemEdit(alarmItem, true) }
.background(MaterialTheme.colorScheme.surface)
.wrapContentHeight(),
shape = MaterialTheme.shapes.small,
elevation = CardDefaults.elevatedCardElevation(5.dp),
colors = CardDefaults.cardColors(containerColor = backgroundColor),
) {
ConstraintLayout(modifier = Modifier.fillMaxSize()) {
val refLabel = createRef()
val refBell = createRef()
val refAlarmTime = createRef()
val refAlarmActive = createRef()
val refAmPm24h = createRef()
val refWeekdays = createRef()
}
}
}
现在,长按回调:
private fun AlarmItemLongClicked(id: Long) {
// get the list of alarms
//List<AlarmItem> alarmItems = parent.alarmViewModel.getAlarmList().getValue();
//if (alarmItems==null) return;
// Update the list of the selected items - simply toggle
parent!!.alarmViewModel.toggleSelection(id)
// Modify toolbar according to number of selected items
parent!!.UpdateOptionMenu()
// Inform the ViewModel that the selection List was changed
parent?.alarmViewModel?.selectToggleObserve()
}
在 ViewModel 上,从所选 ID 列表中添加/删除 ID 的代码:
public void toggleSelection(long id){
int index = selectedItems.indexOf((int)id);
if (index >=0)
selectedItems.remove(index);
else
selectedItems.add((int)id);
LiveSelectedItems.setValue(selectedItems);
selectToggleObserve();
}
以上属性的定义:
private final MutableLiveData<ArrayList<Integer>> LiveSelectedItems;
private final ArrayList<Integer> selectedItems;
State
需要知道其值何时更新,但它无法跟踪
List
中的更改。要触发 State
更新,您需要创建一个新的集合实例,而不是使用相同的 LiveData
实例更新 ArrayList
。查看模型:
private final MutableLiveData<ArrayList<Integer>> liveSelectedItems = new MutableLiveData<>(new ArrayList<>());
public final LiveData<ArrayList<Integer>> selectedItems = liveSelectedItems;
public void toggleSelection(int id) {
var currentList = Objects.requireNonNull(liveSelectedItems.getValue());
var newList = new ArrayList<>(currentList);
int index = currentList.indexOf(id);
if (index >= 0) {
newList.remove(index);
} else {
newList.add(id);
}
liveSelectedItems.setValue(newList);
}
可组合示例:
val selectedItems by viewModel.selectedItems.observeAsState(ArrayList())
Column {
repeat(10) { index ->
Card(
modifier = Modifier
.padding(5.dp)
.fillMaxWidth()
.clickable { viewModel.toggleSelection(index) },
) {
Text("Item $index selected: ${selectedItems.contains(index)}")
}
}
}