3

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

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

4

2 回答 2

3

您是否考虑过一种更模型化的方法?我的意思是,如果您使用类似 a 的东西,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而不是轻弹,因为后者会给出错误的结果,考虑到当前的滚动量。使用映射将使解决方案与您可能使用的任何定位方案无关,并且还将支持任意级别的嵌套对象。

于 2017-08-29T20:40:43.470 回答
1

dtech 的答案是正确的。它很容易与漂亮的捕捉动画相结合,也很容易为 x 方向轻弹进行修改。此外,用户可能故意轻弹或拖动轻弹。在我的例子中,C++ 代码控制了网格布局中项目的文本或显示效果,包含在 flickable 中。当 C++ 代码发出信号时,flickable 需要很好地轻弹,但如果用户故意拖动或轻弹,则不需要。这是 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;
}
于 2019-05-07T12:17:04.303 回答