Qt Design Studio - Sketch Bridge教程 第1部分
- 1.1 一个简单的按钮
- 1.2 第一个导入
- 1.3 When Conditions
-
- 默认状态条件
- 悬停状态条件
- 按下状态条件
本文翻译自:Qt Design Studio - Sketch Bridge Tutorial Part 1
原文作者:Brook Cronin
校审:Amos Yang
欢迎来到Qt Design Studio Sketch Bridge教程,学习这个教程需要安装:商业版Qt Design Studio 1.5、Sketch Bridge、 macOS并且安装Sketch (本文基于66.1版)。
在本教程中,我想向您展示如何建立一个Sketch的项目,开发一个简单的可以导出并导入到Qt Design Studio (以下简称qds)的项目,使用符号和实例进行适当的组件化并基于qds迭代建立一个更复杂的场景。我还将介绍我从其他用户那里遇到的一些最常见的问题,以及我在使用Bridge Plugin开发时的一些技巧。
开始之前,有一个很重要的问题需要澄清。尽管Sketch允许设计师以自由开放的方式来实现自己的设计概念,但是为了在qds中建立一个细节完美的且基于组件式的设计,必须采用一些固定的模式来组织和开发您的项目。虽然不需要非常复杂的知识,但是要做好它确实需要一些时间和知识。我希望本教程将为您提供必要的经验,使您的设计更接近这一点。接下来,让我们直接开始吧。
1.1 一个简单的按钮
在第一步中,我们将设计一个按钮,作为项目的基础。我们在Sketch中开始这个项目,打开Sketch应用程序并创建一个新的空白文件。
首先,通过拖拽一个矩形来创建默认的按钮背景,我们要确保按钮的大小正确,然后将其设置为一个符号,在创建该符号后,让我们删除这个实例,直接在该主符号上继续。
添加矩形
然后我们可以在按钮上添加一些漂亮的圆角、创建渐变、添加阴影和高亮。在开始视觉设计之前,我想分享第一个技巧。为了更容易观察设计,我们可以把画板拉大一些,检查阴影,并给该符号添加工作背景,选一种我们不打算在设计中使用的颜色,使其与我们的设计颜色形成鲜明对比,比如这个淡粉色。
这里我们必须取消选择这两个选项,我们不希望这个背景被导出或在以后使用符号时出现。整理好我们的设计空间后,可以修整这些圆角,添加简单的渐变和阴影。
设计按钮
现在我们的按钮有了默认的背景状态,让我们再创建两个使用状态,悬停和按下。
我们可以复制原始矩形、重命名图层,然后将它们左右摆放,方便查看设计变更效果,为方便起见,我们可以拉大符号的宽度以并排放置按钮,完成设计后我们再调整大小。
调整Artboard大小
现在设置好了,我们可以通过微调渐变颜色来改变悬停和按下状态下的按钮背景,直到我们拥有三个版本的按钮。我认为用户体验在这方面没有真正的规则,只要这些状态是一致的,并与整体的UI设计相比配,我将遵循的逻辑是悬停状态比正常状态亮一点,按下状态稍微暗一点。
在这一步中,我还将清楚地命名了各个图层,并作为QML的ID,之后我们将对此进行详细介绍。
添加变化
创建好三个背景后,让我们把它们重新放在一起,因为我希望它们按照这一方式导出。现在我们将添加一个hotspot 作为顶层图层,在导入Design Studio时它将自动转换为MouseArea。
在添加hotspot 时,将目标设置为none很重要,我们希望确保这是按钮的顶层,以正确捕获鼠标事件。
此外,我们还要确保此次按钮的画板足够大,以容纳所有添加的阴影效果、无需剪裁,但要足够接近边缘以确保项目边框不会太大,足够靠近效果边缘最好。
完成后,我们就可以使用简单的按钮来准备Qt Bridge Plugin中的设置。
添加MouseArea
我在人们使用Sketch Bridge时最常见的错误是在一个项目中重复使用qml的id,尽管qds的导入功能可以检测、保留qml id,但仍然建议手动检查所有的qml id,以确保它们是唯一的且有意义。
这里有一个问题,一旦重命名符号的qml id,该符号的每个实例都将拥有重复的id。对此,我的建议是使用一种区分符号和实例的命名方案。
例如,这里我们将确保按钮符号的id为myButton_Symbol,不同的层将其作为前缀并附加状态,例如myButton_Symbol_default等等。因为以后在这个项目中一定会有更多的鼠标区域,让我们把该热点重命名为myButton_Symbol_hotspot,当我们在屏幕上使用按钮作为实例时,我们将确保赋予这些实例与屏幕相关的唯一id,同时还要注意qml ids只能使用可能字符的子集,在本教程中,我们将使用下划线来分隔我们的名称,因为我们知道这种格式符合要求。
当我们重命名这些id时,要确保所有图层都设置为了Child,我们希望为每层设置单独资产,因此我们现在不希望合并任何内容,稍后在设计某些背景时,我们将使用合并以最大程度地减少设计中的单个资产数量,但现在让我们正确设置所有这些qml id,并确保将每个按钮设计的导出类型设置为Child。
根据我的经验,为图层设置和qml一样的id非常有用,这使以后找图更为容易,尤其是当文件接近于一个完整的UI项目会变得非常大而复杂。
创建id
在Qt Bridge插件中,我们还想先在设置页面中设置一些基本内容,这些是将在项目中使用的全局设置,所以我们只需要设置一次。首先,我们需要选择一个导出路径,让我们创建一个项目文件夹,稍后我们可以在这里创建Design Studio项目,在这里我们将创建一个导出文件夹,并导入我们想要的资产和元数据。要创建文件夹,您需要使用快捷键shift+cmd+n。
现在让我们把其余设置都保留为默认设置,在本教程中我们将使用png格式,此时我们已经准备好回到我们的Bridge 插件的主面板并进行第一次导出。
全局设置
正确设置了所有qml id和导出类型后,我们就可以导出组件并将其导入Design Studio,在这里我们将添加一些状态并对按钮进行测试,然后再在Sketch中进行设计。
点击导出,然后转到Design Studio。
第一个导出
1.2 第一个导入
首先在Design Studio中,我们可以创建一个空项目来导入我们的Sketch设计,让我们进入主页并点击New Project按钮,这将启动向导,我们选择默认的空项目。
我们选择项目文件夹作为项目的存储位置,然后其余的设置保留为默认值。向导完成后,我们将自动切换到项目附带的默认ui.qml文件,要导入我们的sketch设计,我们现在可以进入assets面板,并添加新的资产,然后导航到我们从Sketch导出设计的文件夹。
创建项目
我们需要的文件是.metadata,只有在Design Studio商业版本中启用Importer插件时才可选择。
要检查这一点,您可以在文件类型过滤器组合框中查看可用的导入,如果存在元数据类型,那么您就有了正确的设置,我们可以选择该文件来启动导入器面板。
对于第一个导入,我们将使用默认设置,我们将在禁用合并的情况下导出元数据和资产,但由于我们希望在Design Studio中立即开始处理所有后续导入,我们将启用合并功能,这样就不会意外覆盖qds中的任何内容。
选择metadata
导入metadata
导入完成后,我们可以暂时关闭导入器,并查看导入的文件,这些文件所在的文件夹与导出文件夹同名。如果我们导航到这个文件夹,将看到我们的项目,目前我们只有一个按钮组件,所以让我们看一下这个文件,检查我们的导出是正确的。
检查导入
在这个文件中,我们应该有三个用于不同状态的按钮层,以及鼠标区域。默认情况下,Sketch在导出中附加了一个空层,这里它被称为asset,现在我们需要做的第一件事就是删除这一层,因为我们的组件不需要它。
之后,我们需要将鼠标区域设置为启用悬停状态,因为我们确实希望使用悬停状态。让我们通过在导航器中点击鼠标区域,进入属性面板并选择鼠标区域的hover enabled来实现这一点。
因为我们目前处于Base State(基础状态),目前唯一的状态,所以从现在开始,它将应用于我们添加的每个状态。这里可以添加我们需要的状态。我们应该始终尝试为应用使用明确的用户创建状态。
基础状态用于对设计进行更改,我们希望将其应用于所有其他状态,如果当前处于用户创建状态,那么我们在此所做的任何更改都将仅应用于该状态的本地版本。
启用悬停
让我们为这个按钮创建三个状态,分别命名为default、hovered和pressed。
现在我们有这些状态,我们可以改变系统默认状态为用户创建的默认状态,我们可以通过单击状态缩略图上的Action图标,然后选择“make default”,现在每次加载该组件,这将是按钮显示的状态。
添加状态
我们需要为这些状态添加一些逻辑,以便将它们连接到鼠标区域,我们将在下一步中使用Action图标中的when conditions选项来完成这项工作。现在,让我们为每个状态准备设计,因为这是第一个导入,只需简单地在每个状态中显示正确的对应资产层。
最简单的实现方法就是在每个状态下让对应层可见,而其他层不可见。首先让我们通过在状态面板上点击正确的缩略图进入默认状态,,选择该状态后,进入导航器中的图像并逐个选择资产,正确切换每个图层的可见性,因此在默认状态下我们想要的是默认层可见,悬停和 按下设置为不可见。
一旦设置好这些,我们就可以进入到悬停状态,并重复这个过程,使悬停图层成为唯一可见层。最后,我们通过选择按下状态,重复上面的过程,使按下层唯一可见。
设置素材
1.3 When Conditions
现在我们应该准备添加逻辑到这些状态,并将它们关联到鼠标区域,但首先可以点击状态缩略图来快速检查一切是否都设置正确,如果一切都正确,您应该在表单编辑器中只看到适当的层。假设一切正常,让我们将逻辑添加到鼠标区域/状态中,我们将使用“When Conditions”来实现这一点——本质上,这意味着当满足定义的条件时,该状态将是激活的。当情况很快变得非常复杂时,通常您需要添加不止一个条件来恰当地模拟任何有意义的行为,这里您会看到在两种状态中,我们需要评估两个单独的条件以确保我们有正确的行为。我们还需要仔细检查条件是否都是真的和假的。
如果您不熟悉When Conditions及其语法,我想稍微介绍一下这个概念。When Conditions与被称为逻辑运算符的操作符一起工作,您可以在这里了解更多信息
在qml和qds上下文中,意味着我们可以评估几个项目属性的真实性,并将UI转换到适用这些条件的状态下。我们可以看条件是真还是假,是大于还是等于等等。我们还可以利用操作符(AND或者OR)比较多个项目的真实性。
When conditions是按照从左到右和在代码中出现的顺序来评估的,因此,如果不同的状态有两个条件都为真,那么它将选择其中的第一个条件来应用于您的状态。因此,确保每个条件只能在一种状态下成立非常重要。
如果现在听起来有点复杂,那就试着一步一步跟着做,希望到最后您会对when conditions的实用性和功能性有更好的认识。
让我们从添加默认条件开始,我们想要确保当没有鼠标悬停在按钮上并且没有按下鼠标按钮时,会显示默认按钮。这两个条件都应该是“不”,而且都成立,这样鼠标不悬停和按钮不按下就是正确声明。
我们可以通过在条件前添加一个感叹号来定义一个not条件,为了评估两个条件,我们将在它们之间使用一个双&符号。我们现在就来做这个。首先在状态缩略图预览面板中选择默认状态,然后单击Action图标并选择“add when condition”选项,这将启动绑定编辑器,我们可以在这里添加条件。
准确编写条件非常重要,所以我们将使用自动完成功能来确保没有拼写错误。
默认状态条件
所以让我们先输入一个!,紧随其后的是前三个字母是我们要检查的项目,在这种情况下它是鼠标区域,叫做myButton_Symbol_mouseArea,前三个字符输入后,我们应该列出了所有可能的完成项,让我们从列表中选择mouse area。在第一个条件中,我们需要检查鼠标区域的一个名为containsMouse的属性
这将告诉我们用户是否悬停在按钮上。因此,在绑定编辑器中有了鼠标区域之后,我们可以添加一个句号,然后在列表中查找contains mouse属性并选择它。
现在我们有了第一个条件,它检查用户当前没有悬浮在按钮上,具体为:
!myButton_Symbol_mouseArea.containsMouse*
我们还需要评估第二个条件,以确保用户也没有按下按钮,我们可以设置条件来评估这两个事件,在它们之间添加两个&号,现在我们可以重复第一步,因为我们要再一次检查这个鼠标区域。
让我们输入一个!,然后是鼠标区域的第一个字母,这会弹出自动完成列表。再次选择mouse area并添加句号以获得属性列表,这次我们选pressed属性,它告诉我们该按钮当前是否包含已按下的鼠标。
所以第一个按钮的最终条件应该是这样的:
!myButton_Symbol_mouseArea.containsMouse && !myButton_mouseArea.pressed
Default When
当条件本身实际上没有做任何事情时,它只是确保在悬停或按下事件通过后,按钮将重置为默认状态,因为我们的按钮总是在默认状态下启动,现在我们看不到任何变化,所以让我们添加下一组条件来测试按钮。
悬停状态条件
我们的第二个条件要实现悬停按钮,因此要先确保进入正确的状态:点击缩略图面板的悬停状态缩略图,一旦表单编辑器上出现正确的状态,我们就可以添加下一个条件,在这种情况下,当鼠标在鼠标区域上但又不按下时(因为那将是我们按下的状态),我们希望处于悬停状态。
因此,通过单击Action图标、选择add when condition,让我们为该状态再次启动绑定编辑器。打开绑定编辑器后,我们可以使用自动完成功能来确保条件拼写正确,我们想要的第一个条件是检查鼠标是否在鼠标区域上,因此我们要查找的id还是myButton_Symbol_mouseArea
当我们输入前三个字母时,我们将得到文件中可用的项目列表,我们可以向下滚动并选择鼠标区域。一旦选中,我们将在末尾添加句号,这将启动可用属性的列表以进行判断。
我们需要的属性叫做containsMouse,所以我们可以开始键入字符以缩短列表或向下滚动列表并选择它,注意,这一次我们没有加!,因为我们想检查条件是否为真,而!检查条件为假。下面是这个状态的第一个条件:
myButton_Symbol_mouseArea.containsMouse
我们还需要确保当我们按下按钮时不会显示悬停状态,当然,按下按钮时鼠标必须在鼠标区域内,为了区分这两个事件,我们将为状态添加另一个条件。
打开绑定编辑器后,我们可以添加&&,然后开始添加另一个条件,在本例中,第二个条件与之前的默认状态相同,从一个!开始,我们可以再次键入条件!myButton_mouseArea.pressed,以检查按钮是否没被按下。
现在我们应该有了这个状态的完整条件如下:
myButton_mouseArea.containsMouse && !myButton_mouseArea.pressed
它检查鼠标是否悬停在按钮上,但尚未按下,您可以看到唯一的区别是第一个!,这就是为什么我们必须仔细检查when conditions,以确保所有内容都用了正确格式。
悬停When
它检查鼠标是否悬停在按钮上,但尚未按下,您可以看到唯一的区别是第一个!,这就是为什么我们必须仔细检查when conditions,以确保所有内容都用了正确格式。
按下状态条件
最后一个条件是按下状态,这个更简单因为我们唯一要判断的是按钮是否被按下。让我们进入按下状态,再次点击状态面板中的缩略图,通过Action图标启动绑定编辑器,这次我们需要一个简单的条件:
myButton_mouseArea.pressed
按下When
现在所有状态都有了条件,可以通过运行实时预览来测试按钮。目前这个案例中检查正确的状态是否在正确的时间被激活很简单,但更复杂的设计和更微妙的变化仅通过预览就非常困难了。这里有一个小技巧来确保我们处于正确的状态。
首先需要确保我们处于基础状态,我们要添加一个标签以显示当前所处状态,因此我们使用的标签和绑定必须在每个状态下都存在,正确的处理方法是在基础状态面板上点击它,然后转到QML Types库中的Qt-Quick Basics部分,并将文本项拖到按钮顶部的表单编辑器中。
一旦我们确定状态都正确,我们会再次删除它,所以只要它是可读的,看起来什么样并不重要。因此,如果您需要调整大小和颜色以便让标签可读,那现在就去做吧。
标签准备好后我们会添加一个绑定,确保文本项被选中,然后我们可以在属性面板上找到这个项目的文本属性。
现在我们将鼠标悬停在按钮上以显示Action图标,并通过选择设置绑定来启动绑定编辑器,这里我们要做的是用这个文本标签来显示组件的当前状态,可以通过文本来绑定组件的状态属性,另一种更简单的添加绑定方法是用绑定编辑器里的组合框。
让我们使用左边的组合框来选择按钮myButton_Symbol,然后用右边的组合框来选择状态属性,它将自动创建绑定:
myButton_Symbol.state
添加标签
现在我们应该看到,对于我们定义的所有状态,标签都将显示状态名称,我们可以单击缩略图以确保标签在每个状态下都是正确的,然后我们可以测试按钮以确保其准确运行。
点击顶部工具栏上的Live Preview按钮启动实时预览,这将在一个可与之交互的窗口中启动我们的按钮。点击按钮,开始应该在默认状态下,上下移动鼠标时应来回切换默认、悬停状态,按下鼠标按钮会在悬浮和按下之间切换。您应该在不同的状态下看到正确的设计和标签。如果成功了,恭喜您,您已经创建了第一个正确的qds组件:)
Live-Preview
如果不起作用,则需要检查以下两个地方。
- 确保鼠标区域悬停属性在基本状态和所有其他用户创建状态中设置为真。
- 仔细检查您的when conditions是否有拼写错误。
如果所有这些都正确,您应该有一个正常工作的按钮,如果您想再检查您的按钮是否相同,我在这里分享一下示例代码。
在第二篇文章中,我们将回到Sketch,使用这个按钮创建一个包含多个按钮实例的菜单符号,然后将其导入Qt Design Studio后继续开发我们的项目。
所有的项目文件可以在这里找到:
https://www.dropbox.com/sh/onycru7p2s3h1fp/AADAl8thdX8nB8SWsK9Czmnea?dl=0
对于那些对这个qml外观感兴趣的人,下面列出的是源代码:
import QtQuick 2.8Item {
id: myButton_Symbolwidth: 211height: 211state: "default"Image {
id: myButton_Symbol_defaultx: 0y: 0source: "assets/myButton_Symbol_default.png"}Image {
id: myButton_Symbol_hoverx: 0y: 0source: "assets/myButton_Symbol_hover.png"}Image {
id: myButton_Symbol_pressedx: 0y: 0source: "assets/myButton_Symbol_pressed.png"}MouseArea {
id: myButton_Symbol_MouseAreax: 0y: 0width: 211height: 211hoverEnabled: true}states: [State {
name: "default"when: !myButton_Symbol_MouseArea.containsMouse&& !myButton_Symbol_MouseArea.pressedPropertyChanges {
target: myButton_Symbol_hovervisible: false}PropertyChanges {
target: myButton_Symbol_pressedvisible: false}},State {
name: "hover"when: myButton_Symbol_MouseArea.containsMouse&& !myButton_Symbol_MouseArea.pressedPropertyChanges {
target: myButton_Symbol_pressedvisible: false}PropertyChanges {
target: myButton_Symbol_defaultvisible: false}},State {
name: "pressed"when: myButton_Symbol_MouseArea.pressedPropertyChanges {
target: myButton_Symbol_defaultvisible: false}PropertyChanges {
target: myButton_Symbol_hovervisible: false}}]
}