我们在很多的系统中看见可以在屏幕的一个地方长按,然后就可以根据当前显示的上下文弹出一个菜单。菜单中可以有一些选项,比如删除,修改该项。这种一般在ListView或GridView中常见。今天,我们就在这个例程中详细介绍如何实现这个功能。
对ListView来说,我们只需要对它的delegate做一些修改:
Component {
id: listDelegate
ListItem {
id: delegateItem
width: listView.width; height: units.gu(10)
onPressAndHold: ListView.view.ViewItems.dragMode =
!ListView.view.ViewItems.dragMode
Image {
id: pic
height: parent.height - units.gu(1)
width: height
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: units.gu(0.5)
source: image
}
Column {
id: content
anchors.top: parent.top
anchors.left: pic.right
anchors.leftMargin: units.gu(2)
anchors.topMargin: units.gu(1)
width: parent.width - pic.width - units.gu(1)
height: parent.height
spacing: units.gu(1)
Label {
text: name
}
Label { text: description }
Label {
text: '$' + Number(cost).toFixed(2)
font.bold: true
}
}
ListView.onAdd: SequentialAnimation {
PropertyAction { target: delegateItem; property: "height"; value: 0 }
NumberAnimation { target: delegateItem; property: "height"; to: delegateItem.height; duration: 250; easing.type: Easing.InOutQuad }
}
ListView.onRemove: SequentialAnimation {
PropertyAction { target: delegateItem; property: "ListView.delayRemove"; value: true }
NumberAnimation { target: delegateItem; property: "height"; to: 0; duration: 250; easing.type: Easing.InOutQuad }
// Make sure delayRemove is set back to false so that the item can be destroyed
PropertyAction { target: delegateItem; property: "ListView.delayRemove"; value: false }
}
/* create an empty item centered in the image to align the popover to */
Item {
id: emptyItemForCaller
anchors.centerIn: parent
z: 100
}
Component {
id: actPopComp
ActionSelectionPopover {
id: actPop
delegate: ListItems.Standard {
text: action.text
}
actions: ActionList {
Action {
text: "Add 1 dollar"
iconName: "add"
onTriggered: {
PopupUtils.close(actPop);
console.log("Add 1 dollar");
fruitModel.setProperty(index, "cost", cost + 1.0);
}
}
Action {
text: "Deduct 1 dollar"
iconName: "remove"
onTriggered: {
PopupUtils.close(actPop);
console.log("Deduct 1 dollar");
fruitModel.setProperty(index, "cost", Math.max(0,cost-1.0));
}
}
Action {
text: "delete"
iconName: "delete"
onTriggered: {
console.log("delete the item!");
fruitModel.remove(index)
}
}
}
}
}
MouseArea {
anchors.fill: parent
onPressAndHold: {
PopupUtils.open(actPopComp, emptyItemForCaller);
}
onClicked: {
console.log("we can do something else!");
}
}
}
}
从上面的代码中可以看出:
/* create an empty item centered in the image to align the popover to */
Item {
id: emptyItemForCaller
anchors.centerIn: parent
z: 100
}
我们使用了一个空的Item来作为一个placeholder。这个是为了给我们在长按ListView中项时,来提供一个位置显示我们的Popup menu。
当我们长按我们的ListView中的项时,我们可以通过如下的方法来得到事件并弹出我们所需要的Popup:
MouseArea {
anchors.fill: parent
onPressAndHold: {
PopupUtils.open(actPopComp, emptyItemForCaller);
}
onClicked: {
console.log("we can do something else!");
}
}
这里,我们的actPopComp的设计为:
Component {
id: actPopComp
ActionSelectionPopover {
id: actPop
delegate: ListItems.Standard {
text: action.text
}
actions: ActionList {
Action {
text: "Add 1 dollar"
iconName: "add"
onTriggered: {
PopupUtils.close(actPop);
console.log("Add 1 dollar");
fruitModel.setProperty(index, "cost", cost + 1.0);
}
}
Action {
text: "Deduct 1 dollar"
iconName: "remove"
onTriggered: {
PopupUtils.close(actPop);
console.log("Deduct 1 dollar");
fruitModel.setProperty(index, "cost", Math.max(0,cost-1.0));
}
}
Action {
text: "delete"
iconName: "delete"
onTriggered: {
console.log("delete the item!");
fruitModel.remove(index)
}
}
}
}
}
在这里,我们有三个Action的菜单。
运行我们的应用:
整个项目的源码在:https://github.com/liu-xiao-guo/contextmenu