在这一步中,你将添加一个幕布状的覆盖层,单击时会打开。Slint 文件对绘制项具有隐式的 z 顺序。 每个后续项都绘制在先前的项之上。因此第 10 行的 Rectangle 将位于文件中稍后在第 50 行声明的另一项之下。为了营造覆盖图像的幕布效果, 在 Image 之后声明两个矩形,这样 Slint 会将它们绘制在 Image 之上。
TouchArea 元素声明了一个透明的矩形区域,允许 响应用户输入,例如鼠标点击或轻触。该元素将一个回调转发给 MainWindow,指示用户点击了该拼图块。
MainWindow 通过翻转一个自定义的 open_curtain 属性来做出响应。 用于动画化 width 和 x 属性的属性绑定也使用了自定义的 open_curtain 属性。
下表更详细地展示了两种状态:
| open_curtain 值: | false | true |
|---|---|---|
| 左侧幕布矩形 | 通过将 width 设置为父宽度的一半来填充左半部分 | width 为零使矩形不可见 |
| 右侧幕布矩形 | 通过将 x 和 width 设置为父宽度的一半来填充右半部分 | width 为零使矩形不可见。x 向右移动,在动画播放时将幕布滑动打开 |
为了使拼图块可扩展,将硬编码的图标名称替换为在实例化元素时可以设置的 icon 属性。
为了最终的美化效果,添加一个 solved 属性,当玩家找到一对时用于将颜色动画化为绿色调。
将 ui/app-window.slint 文件中的代码替换为以下内容:
slint
component MemoryTile inherits Rectangle { callback clicked; in property <bool> open_curtain; in property <bool> solved; in property <image> icon;
height: 64px; width: 64px; background: solved ? #34CE57 : #3960D5; animate background { duration: 800ms; }
Image { source: icon; width: parent.width; height: parent.height; }
// Left curtain Rectangle { background: #193076; x: 0px; width: open_curtain ? 0px : (parent.width / 2); height: parent.height; animate width { duration: 250ms; easing: ease-in; } }
// Right curtain Rectangle { background: #193076; x: open_curtain ? parent.width : (parent.width / 2); width: open_curtain ? 0px : (parent.width / 2); height: parent.height; animate width { duration: 250ms; easing: ease-in; } animate x { duration: 250ms; easing: ease-in; } }
TouchArea { clicked => { // Delegate to the user of this element root.clicked(); } }}
export component MainWindow inherits Window { MemoryTile { icon: @image-url("icons/bus.png"); clicked => { self.open_curtain = !self.open_curtain; } }}代码使用了 root 和 self。root 指的是组件中最外层 的元素,在本例中为 MemoryTile。self 指的是 当前元素。
代码导出了 MainWindow 组件。这是必需的,以便以后可以从应用程序业务逻辑中访问它。
运行代码会打开一个窗口,其中显示一个矩形,单击时会打开以显示公交车图标。后续的点击会再次关闭和打开幕布。