QML ListView中交替行颜色与平滑高亮矩形的结合难题
QML ListView 同时实现交替行颜色与平滑移动高亮项的难题
我在QML的ListView中尝试同时实现两个看似简单的功能:交替行颜色和平滑移动的高亮项,但结合起来却遇到了不少麻烦。单独使用这两个功能都很容易,但组合在一起就出现了视觉上的问题。
基础示例(仅交替行颜色+普通高亮)
先看一个具备交替行颜色、点击或方向键可切换高亮项的基础示例:
Python 启动代码
import sys from PySide6.QtCore import QUrl from PySide6.QtQml import QQmlApplicationEngine from PySide6.QtWidgets import QApplication if __name__ == '__main__': app = QApplication([]) engine = QQmlApplicationEngine() engine.load(QUrl.fromLocalFile('main.qml')) if not engine.rootObjects(): sys.exit(-1) app.exec()
QML 代码
import QtQuick import QtQuick.Controls.Material import QtQuick.Layouts ApplicationWindow { id: root width: 400 height: 500 visible: true font.family: 'Noto Sans' ListView { id: listView width: root.width height: root.height clip: true focus: true reuseItems: true boundsBehavior: Flickable.StopAtBounds model: [ "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia", "Wikipedia is a free online encyclopedia" ] delegate: Rectangle { height: 40 width: parent.width color: ListView.isCurrentItem ? Material.accent : index % 2 === 0 ? palette.base : palette.alternateBase MouseArea { anchors.fill: parent onClicked: { listView.currentIndex = index } } RowLayout { height: parent.height Label { text: index horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter Layout.preferredWidth: 100 } Label { text: modelData Layout.preferredWidth: 300 } } } } }
这个示例的效果是交替行颜色,点击或方向键切换高亮项,但高亮切换没有平滑过渡:
仅平滑高亮的实现(无交替行颜色)
如果只需要平滑移动的高亮项,只需替换ListView的highlight和delegate部分代码:
// ... highlight: Rectangle { height: 40 width: parent.width color: Material.accent } delegate: Rectangle { height: 40 width: parent.width color: 'transparent' // ... 其余代理内容不变 } // ...
效果是高亮项会平滑移动,但没有交替行颜色:
尝试的组合方案及问题
方案1
尝试让当前项的代理背景透明,同时保留highlight来实现平滑移动:
// ... highlight: Rectangle { height: 40 width: parent.width color: Material.accent } delegate: Rectangle { height: 40 width: parent.width color: ListView.isCurrentItem ? 'transparent' : index % 2 === 0 ? palette.base : palette.alternateBase // ... 其余代理内容不变 } // ...
效果是切换高亮时,当前项变为透明,但高亮块移动过程中会露出下方的交替行颜色,出现视觉断层:
方案2
尝试把highlight的层级设为1,覆盖在代理上方:
// ... highlight: Rectangle { height: 40 width: parent.width color: Material.accent z: 1 } delegate: Rectangle { height: 40 width: parent.width color: index % 2 === 0 ? palette.base : palette.alternateBase // ... 其余代理内容不变 } // ...
效果是高亮块会覆盖在代理上,但移动过程中高亮色和交替行颜色重叠,视觉上显得杂乱:
我觉得这个任务应该没那么复杂,可能是我忽略了某些细节。有没有人遇到过类似问题并找到可行的解决方案?
内容的提问来源于stack exchange,提问作者trin94
相关产品推荐
相关产品推荐

