我的难题一般来说是:通过GridView之外的一些动作,我想根据之前选择的特定模型项或索引来计算GridView中特定委托项的坐标 .
我有一个GridView,其中包含模型中的许多项目 . GridView的委托创建每个项目的缩略图视图 . 单击时,它会显示项目的详细全屏视图 . 我想要一个很好的转换,它显示缩略图从GridView中的位置扩展出来,当详细视图被解除时,缩小回到GridView中 .
诀窍是,详细视图本身是ListView的委托,因此您可以一次在一个屏幕的详细视图之间进行分页 . 这意味着只需调整GridView的委托项目大小或某些内容的解决方案将无效 . 此外,由于您可以寻呼到ListView中的任何项目,因此必须仅基于模型中可用的信息或模型项目的索引来返回GridView(例如,我无法存储用于启动的模拟项目的鼠标的坐标 . 详细的观点或东西) .
扩展动画相当容易,因为委托项目具有用于知道其自己的位置的单击处理程序的MouseArea,因此可以将其传递给启动动画的函数 . 这是我无法弄清楚的反过来:从ListView中的模型项/索引,我如何计算GridView中相关项的坐标?
我在文档中找不到任何似乎可以让您从模型项实例甚至索引访问委托项实例的内容 . GridView具有 indexAt()
,它根据坐标返回索引 . 我想我可以反过来做,但它似乎不存在 .
这是一个更具体的例子 . 道歉;这是我能提出的最准确的代码,它准确地描述了我的问题:
import QtQuick 1.1
Item {
id: window
width: 400
height: 200
state: "summary"
states: [
State { name: "summary"; },
State { name: "details"; }
]
transitions: [
Transition { from: "summary"; to: "details";
SequentialAnimation {
PropertyAction { target: animationRect; property: "visible"; value: true; }
ParallelAnimation {
NumberAnimation { target: animationRect; properties: "x,y"; to: 0; duration: 200; }
NumberAnimation { target: animationRect; property: "width"; to: 400; duration: 200; }
NumberAnimation { target: animationRect; property: "height"; to: 200; duration: 200; }
}
PropertyAction { target: detailsView; property: "visible"; value: true; }
PropertyAction { target: summaryView; property: "visible"; value: false; }
PropertyAction { target: animationRect; property: "visible"; value: false; }
}
},
Transition { from: "details"; to: "summary";
SequentialAnimation {
PropertyAction { target: summaryView; property: "visible"; value: true; }
// How to animate animationRect back down to the correct item?
PropertyAction { target: detailsView; property: "visible"; value: false; }
}
}
]
Rectangle {
id: animationRect
z: 1
color: "gray"
visible: false
function positionOverSummary(summaryRect) {
x = summaryRect.x; y = summaryRect.y;
width = summaryRect.width; height = summaryRect.height;
}
}
ListModel {
id: data
ListElement { summary: "Item 1"; description: "Lorem ipsum..."; }
ListElement { summary: "Item 2"; description: "Blah blah..."; }
ListElement { summary: "Item 3"; description: "Hurf burf..."; }
}
GridView {
id: summaryView
anchors.fill: parent
cellWidth: 100
cellHeight: 100
model: data
delegate: Rectangle {
color: "lightgray"
width: 95; height: 95;
Text { text: summary; }
MouseArea {
anchors.fill: parent
onClicked: {
var delegateRect = mapToItem(window, x, y);
delegateRect.width = width; delegateRect.height = height;
animationRect.positionOverSummary(delegateRect);
detailsView.positionViewAtIndex(index, ListView.Beginning);
window.state = "details";
}
}
}
}
ListView {
id: detailsView
anchors.fill: parent
visible: false
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem
model: data
delegate: Rectangle {
color: "gray"
width: 400; height: 200;
Column {
Text { text: summary; }
Text { text: description; }
}
MouseArea {
anchors.fill: parent
onClicked: {
// How do I get the coordinates to where animationRect should return?
summaryView.positionViewAtIndex(index, GridView.Visible);
window.state = "summary";
}
}
}
}
}
有任何想法吗?我可能只是以错误的方式解决这个问题 . 如果我特意做的事情是不可能的,还有其他方法我应该设计这个吗?谢谢!
编辑:我有过的一些想法(我认为没有一个是可行的):
-
使用
Component.onCompleted
和Component.onDestruction
保留所有创建的委托项的列表 . 为了有用,它应该是模型项或index =>委托项的映射 . 麻烦的是,basic types docs(特别是variant)似乎表明这种 Map 不可能用纯QML创建 . 所以听起来这意味着将此 Map 创建为C类并在QML中使用委托组件中的onCompleted
/onDestruction
以使其保持最新 . 对于应该简单的事情来说,似乎有点危险和苛刻 . -
This mailing list post似乎表明Flickable的
contentItem
属性可用于枚举委托项 . 然后我发现this post称这是不好的做法 . 我怀疑这将是一个合法的解决方案 . 看起来太可靠了,无法可靠地工作 .
这就是我到目前为止所做的一切 .
4 回答
经过一些调查后,事实证明
contentItem
确实为Flickable保存了实例化的代理 . 正如我上面所说,我在下面发布了这个hacky解决方案的完整代码,但我更好的方式 . 非常重要的一点是GridView中新的getDelegateInstanceAt()
函数 .请告诉我有一种更健壮的方式!
如果有人对如何在C中完成此操作感兴趣,这里有一个快速片段:
重要的是要注意(以及发布此内容的主要原因),从
QQuickItem
访问children()
将调用QObject::children()
方法,该方法不一定返回与QQuickItem::childItems()
相同的对象 . 也许有人发现这很有用,它肯定会在四天前帮助我...... :)经过短短几个月的QML编程,我已经提出了这个解决方案,类似于OP的解决方案,但无论如何我都会发布它,希望它可以帮助其他人整理这个东西 .
此示例中基本上有三个组件:
GridView
显示可视组件(查看器),Item
包含QObjects
(数据)列表,Component
包含彩色Rectangle
(委托) .查看器获取数据并显示它创建委托 . 遵循此模式,更改委托内容的最简单方法是访问其数据 . 要访问委托的数据,必须首先到达
listmodel
对象,在此示例中,可以通过grid.children[1]
访问(不确定为什么它不在grid.children[0]
,但这只是一个细节),最后通过访问权限委托grid.children[1].list_model[index]
. 这可以方便地打包在getChild()
函数中 .最后的建议是从开发开始以来几乎为所有事情提供有意义的
objectName
. 这种做法使调试变得更加容易,即使它是邪恶的,也允许从C++
访问数据 .对于QML类型ListView,以下简单函数可以获取特定索引处的委托实例:
以下是一个QML测试示例,该示例使用上述函数,添加了基于Qt 5.5的错误检查和日志记录代码:
虽然上述函数适用于这些简单的“fruitModel”和“fruitView”对象,但在处理更复杂的ListModel和ListView实例时可能需要进一步增强 .