QML Book 第五章 动态元素 3

5.2 状态和过渡

通常,用户界面的某些部分可以在状态中描述。状态定义一组可以由特定条件触发的属性更改。可以有一个过渡连接着这些状态的改变,过渡定义了这些更改应该是如何激活的,或者应该应用任何其他的操作。当进入到一个状态时,动作(Actions)也可以被应用。

5.2.1 状态

在QML中使用状态(State)元素定义状态,它是需要绑定到任何 item 元素的状态数组(states)属性。状态通过名为 state 属性的值来标识,并且以元素的最简单的形式一系列属性变化组成。默认情况下 state 的值为空字符串。

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

通过将一个新的已定义的状态名赋给带有状态的元素的 state 属性来改变状态。

** 注意: **
切换状态的另一种方法是使用状态元素的 when 属性。可以将 when 属性设置为一个表达式,该表达式求值为 true 时,该状态就会被应用。

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

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

例如,交通灯可能有两个信号灯。上面的一个信号是红色的,而下一个信号的信号是绿色的。在这个例子中,两盏灯都不应该同时亮。让我们看一下状态图。

trafficlight_states

当系统被打开时,它会自动进入到作为默认状态的停止模式。停止状态将 light1 更改为红色和 light2 到黑色(off)。外部事件现在可以触发状态切换到 “go” 状态。在 “go” 状态中,我们将颜色属性从 light1 更改为黑色(off)和 light2 到绿色,以表明现在行人可以通过了。

为了实现这个场景,我们开始为2个灯光勾画用户界面。为了简单起见,我们使用了两个矩形(矩形的宽度和高度相同,这意味着它是一个正方形),设置 radius 属性的值为宽度的一半。

    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”状态,在这个状态中,每个状态都改变了红色或绿色的红绿灯。我们设置状态属性,以确保我们的交通灯的初始状态是 stop 状态。

** 注意: **
我们也可以通过设置一个 “go” 的状态来达到同样的效果,并且不提供显式的 “stop” 状态,即将 light1 的颜色设置为红色,并将 light2 的颜色设置为黑色。初始状态 “由初始属性值定义的状态” 将作为 “停止” 状态。

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

我们现在能够成功地改变交通信号灯的状态。为了让UI更有吸引力,看起来更自然,我们应该添加一些动画效果的过渡。这些过渡可以由状态更改来触发。

** 注意: **
可以使用一个简单逻辑的脚本来替换 QML 状态。开发人员很容易落入这种陷阱:写的代码更像一个 JavaScript 程序而不是一个 QML 程序。

5.2.2 过渡

可以将一系列的过渡(或者叫转换)添加到每个项目中。过渡是由状态更改触发执行的。我们可以定义一个特定的过渡,可以使用 from: 和 to: 属性来确定应用哪个状态更改。这两个属性就像一个过滤器,当过滤器为真时,将应用转换。我们也可以使用 “” 来表示 “任意状态”。例如, from:""; to:"*",表示从任何状态到任何状态,这恰巧是 from 和 to 属性的默认值,这意味着转换会被被应用到每个状态的改变。

对于这个例子,我们希望在将状态从 “go” 切换到 “stop” 时,使颜色发生变化。对于另一个相反的状态更改(“stop”到“go”),我们希望保持颜色立即更改的效果,因此不需要应用转换。我们限制了使用 from 和 to 属性的转换,只过滤从 “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”的转换时,尝试点击UI。你会看到这种变化会马上发生。

trafficlight_transition

我们可以用这个 UI 来尝试新的功能,例如,把不活跃的光缩小,放大活跃的光。为此,我们需要添加另一个属性更改来扩展状态,并在转换过程中处理缩放属性的动画。另一种选择是添加一个 “注意” 状态,在其中添加闪烁黄色的灯光。为此,我们需要向转换中添加一个顺序动画,使其在一秒钟内转换为黄色(“to”动画的属性,一秒后变为黑色)。也许我们还想改变一下缓冲曲线,让这个例子看起来更有效果。

本章完

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容