Have you considered a more model-ar approach to this? I mean if you use something like a ListView
you can simply change the currentItem
at which point the view will automatically scroll to it if it is out of the visible range.
Additionally, it will only load the text elements that are in the visible range, saving on some memory.
But even with your current approach it won't be that complex to ensure visibility.
Flickable {
id: flick
anchors.fill: parent
contentHeight: col.height
function ensureVisible(item) {
var ypos = item.mapToItem(contentItem, 0, 0).y
var ext = item.height + ypos
if ( ypos < contentY // begins before
|| ypos > contentY + height // begins after
|| ext < contentY // ends before
|| ext > contentY + height) { // ends after
// don't exceed bounds
contentY = Math.max(0, Math.min(ypos - height + item.height, contentHeight - height))
}
}
Column {
id: col
Repeater {
id: rep
model: 20
delegate: Text {
id: del
text: "this is item " + index
Keys.onPressed: rep.itemAt((index + 1) % rep.count).focus = true
focus: index === 0
color: focus ? "red" : "black"
font.pointSize: 40
onFocusChanged: if (focus) flick.ensureVisible(del)
}
}
}
}
The solution is quick and cruddy, but it will be trivial to put it into production shape. It is important to map to the contentItem
rather than the flickable, as the latter would give the wrong results, taking the amount of current scrolling into account. Using mapping will make the solution agnostic to whatever positioning scheme you might be using, and will also support arbitrary levels of nested objects.