QML中ListModel更新时间戳不触发add Transition的实现方法问询
核心问题根因
你当前触发不必要add动画的核心原因是onNumNotificationsChanged回调里执行了全量clear() + 重新insert()操作,等于每次更新数据都把整个列表重建,自然所有条目都会触发add过渡。你可以选择以下任意方案解决时间更新的需求,同时避免多余动画:
方案1:存储绝对时间戳,委托内动态计算相对时间(最推荐)
该方案完全不需要频繁更新模型,从根源避免触发动画:
- 模型中不再存储动态变化的相对分钟数,改为存储通知发布时的绝对Unix时间戳,该值固定,通知创建后不会变更
- 在列表委托中新增定时器,每分钟用当前时间减去绝对时间戳计算最新相对时长,直接更新文本即可
示例代码:
property int numNotifications: backend_service.num_notifications onNumNotificationsChanged: { // 改为增量插入,只加新增通知,不要全量清空 for(var x=0; x<numNotifications; x++) { var notif = backend_service.notifications.get(x); // 用通知唯一标识判断是否已存在,避免重复插入 var isExist = false for(var i=0; i<notificationModel.count; i++) { if(notificationModel.get(i).notifId === notif.id) { isExist = true break } } if(!isExist) { // 插入时存固定的绝对时间戳,不要存动态的相对时间 notificationModel.insert(0, { "notifId": notif.id, "name":notif.name, "createTimestamp": notif.createTimestamp }) } } } Rectangle { height: 500 width: 0.90 * parent.width anchors { top: parent topMargin: 30 left: parent.left leftMargin: 45 } ListView { anchors.fill: parent model: notificationModel delegate: notificationDelegate spacing: 30 add: Transition { NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 } } } } ListModel { id: notificationModel } Component { id: notificationDelegate Row { spacing: 20 Text { text: name; color: "white" } Text { color: "white" // 动态计算相对分钟数 text: Math.floor((Date.now()/1000 - createTimestamp) / 60) + "分钟" Timer { interval: 60000 // 每分钟刷新一次 running: true repeat: true onTriggered: parent.text = Math.floor((Date.now()/1000 - createTimestamp) / 60) + "分钟" } } } }
方案2:调用ListModel的set()方法更新指定字段
如果你确实需要把相对时间存在模型里,直接调用ListModel.set(index, propertyObject)方法更新指定条目指定字段即可,该方法只会触发dataChanged信号,不会触发条目新增的add过渡动画:
// 每分钟执行一次的时间更新逻辑 function updateAllNotificationTime() { for(var i=0; i<notificationModel.count; i++) { var curNotif = notificationModel.get(i) // 从后端拿到对应通知的最新时间 var latestTime = backend_service.getNotifLatestTime(curNotif.notifId) // 仅更新time字段,不会触发add动画 notificationModel.set(i, {"time": latestTime}) } }
注意不要调用remove+insert或者clear+全量插入的逻辑,只有纯set操作不会触发add动画。
方案3:直接绑定后端通知对象的属性
如果后端返回的notif对象的time字段是Qt元属性(带有notify信号),可以直接把该对象存在模型中,委托内直接绑定属性即可自动更新,无需手动修改模型:
// 插入时存储原始通知对象 notificationModel.insert(0, {"name":notif.name, "rawNotif": notif}) // 委托内直接绑定后端属性 Text { text: rawNotif.time; color: "white" }
只要后端更新time字段时触发了对应notify信号,前端文本会自动刷新,完全不需要操作模型。
内容的提问来源于stack exchange,提问作者Evan Krause
相关产品推荐
相关产品推荐

