Repeater,在对于需要生成多个 Item,但又不适合 ListView 的情况是很适用的。对于 Repeater 需要嵌套不同种类的 Delegate 的情况,有一些不同的解决方案。
例如,你针对不同的数据需要生成不同的 Item A 或者 Item B,那么一种选择就是把他们都作为子 Item 放到 Delegate 里面,然后选择性的进行 visible 的设置,来达到只现实一个的目的。这样带来的缺点也是显而易见的:
- 需要真的实际创建多个并不使用的 Item
- 对不同的 Item 设置值的时候,可能并不一定会有适合当前不显示的这个 Item 的值。例如,某项属性并不见于 Type B中,在实现的时候却不得不放进一个 dummy value 来避免程序错误。
而另一种选择就是,会选择 Repeater 嵌套一个 Loader ,用 loader 来动态的选择加载某个源文件,或者 Component,通过使用 Loader 的 source / setSource / sourceComponent 来实现。
但是如果你要进行多层次的嵌套,也即在 Loader 里面再套一个 Repeater,就会出现一个奇妙的现象。
举两个例子。
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.10
GridLayout {
columns: 2
Repeater {
model: [[1], [2], [3, 4, 5], [4], [5, 6]]
delegate: Component {
id: comp
Repeater {
model: modelData
Label {
text: modelData
}
}
}
}
}
上面是一个不使用 Loader 的嵌套 Repeater,下面则是一个使用 Loader 的嵌套 Repeater。
import QtQuick 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.10
GridLayout {
columns: 2
Repeater {
model: [[1], [2], [3, 4, 5], [4], [5, 6]]
delegate: Loader {
id: loader
sourceComponent: comp
Component {
id: comp
Repeater {
model: modelData
Label {
text: modelData
}
}
}
}
}
}
这两个代码最终的显示效果,是不一样的。前者可以正常显示表格,就仿佛内层的Repeater 的元素就是在 GridLayout 里一样。
而后者所有的元素都挤在了一起。
原因大概是因为使用了 Loader 的情形下,Loader 本身在层次关系中占有了一层,就像 一个普通的 Item。Loader 内部的 Repeater 并不能跨越 Loader 本身把内部的 Item 添加给 GridLayout。事实上,如果你在代码中把 Loader 直接改成 Item 就可以获得后图一样的效果,可以印证这一点。
只能说并没有一个好办法能够解决这样的问题,最好的解决办法,还是直接把 Model 扁平化只使用一层 Repeater 和 Loader 的组合。