如何使Flickable确保项目内部的可见性?

时间:2017-08-29 19:06:56

标签: qt qml flickable

我有一个Flickable,其中包含大量TextField个对象,这些对象布在一列中,每个TextField都锚定在前一个TextField的底部。一切都工作得很好,除了当我使用tab键浏览这些字段时,最终焦点转移到Flickable的可见矩形之外的TextField,然后用户无法看到光标直到它们手动向下滚动Flickable。

基本上我正在寻找某种“.ensureVisible()”方法,这样当TextField接收焦点时,Flickable会自动滚动,以便刚刚聚焦的TextField完全可见。

2 个答案:

答案 0 :(得分:2)

您是否考虑过更具模范性的方法?我的意思是,如果您使用类似ListView的内容,则只需更改currentItem,如果视图超出可见范围,视图将自动滚动到该视图。

此外,它只会加载可见范围内的文本元素,从而节省了一些内存。

但即使使用您当前的方法,确保可见性也不会那么复杂。

  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)
        }
      }
    }
  }

解决方案快速而且粗糙,但将其投入生产形状将是微不足道的。映射到contentItem而不是flickable很重要,因为后者会给出错误的结果,将当前滚动的数量考虑在内。使用映射将使解决方案与您可能使用的任何定位方案无关,并且还将支持任意级别的嵌套对象。

答案 1 :(得分:1)

dtech的答案很明确。 它可以轻松地与漂亮的快照动画结合使用,并且也可以轻松地针对x方向的可修改对象进行修改。此外,用户可能会故意轻弹或拖动轻弹。就我而言,C ++代码控制可滑动对象中包含的网格布局中项目的文本或显示效果。当C ++代码发出信号时,可轻弹功能需要很好地轻弹,但如果用户故意拖动或轻弹,则不需要轻弹。这是dtech的功能,可沿x方向轻弹:

function ensureVisible(item) {
    if (moving || dragging)
        return;
    var xpos = item.mapToItem(contentItem, 0, 0).x
    var ext = item.width + xpos
    if ( xpos < contentX // begins before
              || xpos > contentX + width // begins after
              || ext < contentX // ends before
              || ext > contentX + width) { // ends after
        // don't exceed bounds
        var destinationX = Math.max(0, Math.min(xpos - width + item.width, contentWidth - width))
        ensureVisAnimation.to = destinationX;
        ensureVisAnimation.from = contentX;
        ensureVisAnimation.start();
    }
}
//This animation is for the ensure-visible feature.
NumberAnimation on contentX {
    id: ensureVisAnimation
    to: 0               //Dummy value - will be set up when this animation is called.
    duration: 300
    easing.type: Easing.OutQuad;
}