QML 中类似 MacOS dock 的组件

MacOS dock-like component in QML

使用 QtQuick,我在转发器中有一排 5 张图像。我想在悬停时实现类似于 MacOS 停靠动画的动画。这里有一张图片供参考:

为了进一步细分,这就是我要完成的工作。这些图像在悬停时应如下所示:

这是我目前的代码

  Row {
    spacing: 2
    anchors.bottom: parent.bottom
    anchors.bottomMargin: 30
    anchors.horizontalCenter: parent.horizontalCenter

    Repeater {
      id: iconRepeater
      model: iconColors()
      Image {
        source: "icons/" + modelData + ".png"
        scale: mouseArea.containsMouse ? 1.5 : 1.0
        MouseArea {
          id: mouseArea
          anchors.fill: parent
          hoverEnabled: true
          onClicked: endTimer()
        }
        Behavior on scale {
          PropertyAnimation {
            duration: 75
          }
        }
      }
    }
  }

这会扩展您悬停在上面的图像,但我似乎无法影响邻居。任何建议表示赞赏!

可能是这样的:

Row {
    anchors {
        bottom: parent.bottom
        left: parent.left
        right: parent.right
    }

    Repeater {
        id: rep
        model: ['red', 'yellow', 'pink', 'green', 'teal', 'orchid', 'blue', 'orange']
        property int currentIndex: -10

        delegate: Rectangle {
            anchors.bottom: parent.bottom
            // Calculate the width depending on the currently hovered element
            width: (rep.currentIndex === index ? 100 : ((rep.currentIndex - index) === 1 || (rep.currentIndex - index) === -1 ? 80 : 50))
            height: width
            radius: width / 2
            color: modelData
            MouseArea {
                anchors.fill: parent
                hoverEnabled: true
                // onEntered/Exited did not react. This will work.
                onContainsMouseChanged: {
                    if (containsMouse) rep.currentIndex = index
                    else rep.currentIndex = -10 // -10 is safe
                }
            }
            // Makes the movement smooth
            Behavior on width {
                NumberAnimation {}
            }
        }
    }
}

我试着在代码中加入必要的解释作为注释。 唯一需要一些 tweeking 的是,当第一次调整大小时,这些点将最初移动。把它放在一个轻弹上,并为正确的位置处理做一些体力劳动可以解决这个问题。基本上,当鼠标进入时,您需要将 flickable 移动宽度变化的一半(在我的例子中约为 55 左右),当鼠标再次离开时,将其移动到右侧。

您也可以使用 ListView 执行此操作,最有可能,但由于背景的估计大小不断变化,正确定位可能更具挑战性。

我建议一个更强大的解决方案,您可以在其中控制缩放因子以及影响的传播和衰减:

  Column {
    Slider {
      id: foff
      from: 1
      to: 5
      stepSize: 1
      value: 2
      snapMode: Slider.SnapAlways
    }
    Slider {
      id: sf
      from: 0.5
      to: 2.5
      stepSize: 0.5
      value: 0.5
      snapMode: Slider.SnapAlways
    }
    Slider {
      id: dmp
      from: 1
      to: 5
      stepSize: 1
      value: 1
      snapMode: Slider.SnapAlways
    }
  }

  Row {
    id: row
    anchors.bottom: parent.bottom
    anchors.bottomMargin: 30
    anchors.horizontalCenter: parent.horizontalCenter

    property int falloff: foff.value // how many adjacent elements are affected
    property int current: -1
    property real scaleFactor: sf.value // that's how much extra it scales
    property real damp: dmp.value // decay of influence 

    Repeater {
      id: iconRepeater
      model: 10
      Rectangle {
        width: 50 * pseudoScale
        height: width
        anchors.bottom: parent.bottom
        color: "red"
        border.color: "black"
        property real pseudoScale: {
          if (row.current == -1) return 1
          else {
            var diff = Math.abs(index - row.current)
            diff = Math.max(0, row.falloff - diff)
            var damp = row.falloff - Math.max(1, diff)
            var sc = row.scaleFactor
            if (damp) sc /= damp * row.damp
            diff = diff / row.falloff * sc + 1
            return diff
          }
        }
        MouseArea {
          id: mouseArea
          anchors.fill: parent
          hoverEnabled: true
          onContainsMouseChanged: row.current = containsMouse ? index : -1
        }
        Behavior on pseudoScale {
          PropertyAnimation {
            duration: 150
          }
        }
      }
    }
  }