Skip to content

美化牌面

在这一步中,你将添加一个点击时会打开的帘幕式覆盖层。Slint 文件在绘制项目时有一个隐式的 z 顺序。 每个后续项目都绘制在前一个项目之上。因此,第 10 行的 Rectangle 会位于文件中第 50 行 之后声明的另一个 Rectangle 之下。为了营造覆盖图像的帘幕效果, 请在 Image 之后声明两个矩形,这样 Slint 会把它们绘制在 Image 之上。

TouchArea 元素声明了一个透明的矩形区域,用于 响应用户输入,例如鼠标点击或触摸。该元素会向 MainWindow 转发一个回调,表明用户点击了这张牌。

MainWindow 通过翻转自定义的 open_curtain 属性来做出反应。 动画 width 和 x 属性的属性绑定也使用自定义的 open_curtain 属性。

下表更详细地展示这两种状态:

open_curtain 值: false true
左侧帘幕矩形 通过将宽度 width 设为父级宽度的一半来填充左半部分 宽度为零会使矩形不可见
右侧帘幕矩形 通过将 x 和 width 设为父级宽度的一半来填充右半部分 width 为零会使矩形不可见。x 向右移动,在播放动画时滑开帘幕

为了让牌具有可扩展性,请将硬编码的图标名称替换为一个可在实例化元素时设置的 icon 属性。

作为最后的润色,添加一个 solved 属性,用于在玩家找到一对匹配的牌时将颜色动画过渡到一种绿色调。

将 ui/app-window.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 组件。这是必要的,以便你稍后可以从应用业务逻辑中 访问它。

运行代码会打开一个窗口,其中的矩形在点击时会打开以显示公交车图标。后续点击会再次合上和打开帘幕。


© 2026 SixtyFPS GmbH