# 状态和过渡

通常,用户界面的一部分可以用状态来描述。 状态定义了一组属性变化,并且可以由特定条件触发。

此外,这些状态切换可以附加一个过渡,该过渡定义了如何将这些改变做成动画,或应用其他任何动作。 当进入状态时,也可以应用动作。

# 状态

在QML中,可以使用State元素定义状态,该元素需要绑定到任何项目元素的states数组上。

状态通过状态名称来标识,最简单的形式是由元素上的一系列属性更改组成。 默认状态由元素的初始属性定义,并命名为 ""(一个空字符串)。

Item {
    id: root
    states: [
        State {
            name: "go"
            PropertyChanges { ... }
        },
        State {
            name: "stop"
            PropertyChanges { ... }
        }
    ]
}

一个元素定义了states,通过将新的状态名称分配给它的state属性来更改状态。

使用when控制状态

另一种控制状态的方法是使用State元素的when属性。 when属性可以设置成一个表达式,当该表达式的计算结果为真时,状态应该被应用。

Item {
    id: root
    states: [
        ...
    ]

    Button {
        id: goButton
        ...
        onClicked: root.state = "go"
    }
}

例如,一个交通灯可能有两个信号灯。 上方的信号使用红色表示停止,下方的信号使用绿色表示行走。 在这个例子中,两个灯不应该同时发光。 我们来看一下状态图。

当系统开机时,它自动进入停止模式,将其作为默认状态。 停止状态将light1变为红色,将light2变为黑色(关闭)。

外部事件现在可以触发状态切换到"go"状态。 在go状态下,将light1的颜色属性改为黑色(关闭),将light2改为绿色,以指示行人现在可以穿过。

为了实现这个场景,开始为这2个灯绘制用户界面。 为简单起见,使用2个矩形,半径设置为宽度的一半(宽度与高度相同,这意味着它是一个正方形)。

Rectangle {
    id: light1
    x: 25; y: 15
    width: 100; height: width
    radius: width / 2
    color: root.black
    border.color: Qt.lighter(color, 1.1)
}

Rectangle {
    id: light2
    x: 25; y: 135
    width: 100; height: width
    radius: width/2
    color: root.black
    border.color: Qt.lighter(color, 1.1)
}

正如状态图中所定义的,希望有两种状态:一种是"go"状态,另一种是"stop"状态,其中每个状态都将交通灯的相应颜色变为为红色或绿色。 将state属性设置为stop以确保交通灯的初始状态是stop状态。

初始化状态

通过将light1的颜色设置为红色,将light2的颜色设置为黑色作为初始状态,可以仅使用"go"状态(而没有明确的"stop"状态)来实现相同的效果。 初始属性值定义了初始状态"",然后将其充当"stop"状态。

state: "stop"

states: [
    State {
        name: "stop"
        PropertyChanges { target: light1; color: root.red }
        PropertyChanges { target: light2; color: root.black }
    },
    State {
        name: "go"
        PropertyChanges { target: light1; color: root.black }
        PropertyChanges { target: light2; color: root.green }
    }
]

在这个例子中,使用PropertyChanges { target: light2; color: "black" }并不真正需要,因为light2的初始颜色已经是黑色的。 在一个状态中,只需要描述属性如何从它们的默认状态(而不是从之前的状态)改变即可。

使用鼠标区域触发状态更改,该区域覆盖整个交通灯并在单击时在开始和停止状态之间切换。

MouseArea {
    anchors.fill: parent
    onClicked: parent.state = (parent.state == "stop" ? "go" : "stop")
}

现在能够成功地改变交通灯的状态。 为了使UI更有吸引力和更自然,应该添加一些带有动画效果的过渡。 状态变化可以触发过渡。

使用脚本

可以使用脚本而不是QML状态来创建类似的逻辑。 然而,在描述用户界面方面,QML是一种比JavaScript更好的语言。 在尽可能的情况下,旨在编写声明性代码而不编写命令式代码。

# 过渡

可以向每个项中添加一系列过渡。通过状态更改执行过渡。

可以使用from:to:属性定义可以用来定义特定的状态更改的过渡。这两个属性就像一个过滤器:当过滤器为真时,将应用过渡。还可以使用通配符“*”,表示“任何状态”。

例如,from: "*"; to: "*"表示“从任何状态到任何其他状态”,是fromto的默认值。这意味着这个过渡将应用于每个状态切换。

对于此示例,希望在将状态从“go”切换到“stop”时将颜色变化设置动画。对于其他反向状态更改(“stop”到“go”),希望保持立即颜色更改并且不应用过渡。

使用fromto属性限制过渡,以仅过滤从“go”到“stop”的状态变化。在过渡内部,我们为每个灯光添加了两个颜色动画,这将为状态描述中定义的属性更改设置动画。

transitions: [
    Transition {
        from: "stop"; to: "go"
        // from: "*"; to: "*"
        ColorAnimation { target: light1; properties: "color"; duration: 2000 }
        ColorAnimation { target: light2; properties: "color"; duration: 2000 }
    }
]

可以通过单击UI来更改状态。 从“stop”到“go”,状态会立即应用;从“go”到“stop”,会在执行过渡时更改状态。 因此,请尝试在状态从“停止”到“运行”的过渡期间单击UI,将看到立即发生改变。

可以此UI上玩些不一样的变化,例如,通过缩小不活动的灯光以突显活动的灯光。

为此,需要添加另一个用于缩放属性更改的状态列表,并且还需要处理过渡中缩放属性的动画。

另一种选择是添加一个“注意”状态,其中指示灯呈黄色闪烁。 为此,需要为一秒钟变为黄色(动画的“to”属性,一秒钟变为“黑色”)这种过渡添加一个串行动画。

也许还可以更改缓动曲线以使其更具视觉吸引力。

最后更新: 11/28/2021, 11:24:19 PM