定位和元素布局#
所有的视觉元素都显示在一个窗口中。x 和 y 属性存储了元素相对于其父元素的坐标。
Slint 通过将父元素的位置添加到元素的位置来确定元素的绝对位置。
如果父元素本身有父元素,那么也会添加到父元素中。这个计算会一直持续到达到顶层元素。
width 和 height 属性存储了视觉元素的大小。
您可以通过两种方式将元素放置在一个完整的图形用户界面中:
显式 - 通过设置
x,y,width和height属性。自动 - 使用布局元素。
显式放置适用于具有少量元素的静态场景。布局适用于复杂的用户界面,并帮助创建可扩展的用户界面。 布局元素表达了元素之间的几何关系。
显式放置#
下面的示例将两个矩形放置在一个窗口中,一个蓝色的和一个绿色的。绿色的矩形是蓝色的子元素:
// 显式定位
export component Example inherits Window {
width: 200px;
height: 200px;
Rectangle {
x: 100px;
y: 70px;
width: parent.width - self.x;
height: parent.height - self.y;
background: blue;
Rectangle {
x: 10px;
y: 5px;
width: 50px;
height: 30px;
background: green;
}
}
}
两个矩形的位置和内部绿色矩形的大小是固定的。
外部蓝色矩形的大小是使用绑定表达式自动计算的 width 和 height 属性。
计算结果是底部左侧的角与窗口的角对齐 —— 它在窗口的 width 和 height 改变时更新。
当指定几何属性的任何一个时,Slint 要求您将单位附加到数字。您可以在两个不同的单位之间进行选择:
逻辑像素,使用
px单位后缀。这是推荐的单位。物理像素,使用
phx单位后缀
逻辑像素会自动缩放,以适应系统配置的设备像素比率。 例如,在现代的高 DPI 显示器上,设备像素比率可以是 2,因此每个逻辑像素占用 2 个物理像素。 在旧屏幕上,用户界面会自动缩放而不需要任何适应。
此外,width 和 height 属性也可以指定为 % 百分比单位,该单位相对于父元素应用。
例如,width: 50% 表示父元素的一半。
x 和 y 属性的默认值是使元素在其父元素内居中。
width 和 height 的默认值取决于元素的类型。
一些元素根据其内容自动调整大小,例如 Image,Text 和大多数小部件。
以下元素没有内容,当它们没有子元素时,默认填充其父元素:
RectangleTouchAreaFocusScopeFlickable
布局元素也默认填充父元素,而不管它们自己的首选大小。
其他元素(包括没有基类的自定义元素)默认使用其首选大小。
首选大小#
元素的首选大小可以使用 preferred-width 和 preferred-height 属性指定。
当没有显式设置时,首选大小取决于子元素,并且是具有更大首选大小的子元素的首选大小,其 x 和 y 属性未设置。
因此,首选大小是从子元素到父元素计算的,就像其他约束(最大和最小大小)一样,除非显式覆盖。
一个特殊的情况是将首选大小设置为父元素的大小,使用 100% 作为值。
例如,这个组件将默认使用父元素的大小:
component MyComponent {
preferred-width: 100%;
preferred-height: 100%;
// ...
}
使用布局自动放置#
Slint 附带了不同的布局元素,它们自动计算其子元素的位置和大小:
VerticalLayout/HorizontalLayout:子元素沿垂直或水平轴放置。GridLayout:子元素在列和行的网格中放置。
您还可以嵌套布局以创建复杂的用户界面。
你可以使用不同的约束条件来调整自动布局,以适应你的用户界面设计。每个元素都有一个最小尺寸、一个最大尺寸和一个首选尺寸。通过以下属性明确设置这些尺寸:
min-widthmin-heightmax-widthmax-heightpreferred-widthpreferred-height
在布局中,具有指定 width 和 height 的任何元素都具有固定的大小。
在布局中有额外的空间时,元素可以沿着布局轴拉伸。您可以使用以下属性在元素和其兄弟元素之间控制此拉伸因子:
horizontal-stretchvertical-stretch
值为 0 表示元素不会拉伸。如果它们都有一个拉伸因子为 0,则所有元素都会均匀拉伸。
这些约束属性的默认值可能取决于元素的内容。如果元素的 x 或 y 没有设置,这些约束也会自动应用到父元素。
布局元素上的常见属性#
所有布局元素都具有以下共同属性:
spacing:这控制子元素之间的间距。padding:这指定了布局内的填充,元素和布局边框之间的空间。
为了更细粒度的控制,padding 属性可以分割为布局的每一边的属性:
padding-leftpadding-rightpadding-toppadding-bottom
VerticalLayout 和 HorizontalLayout#
VerticalLayout 和 HorizontalLayout 元素将其子元素放置在列或行中。默认情况下,它们会拉伸或收缩以占用整个空间。您可以根据需要调整元素的对齐方式。
下面的示例将蓝色和黄色矩形放置在一行中,并均匀地拉伸到 width 的 200 个逻辑像素:
// 默认拉伸
export component Example inherits Window {
width: 200px;
height: 200px;
HorizontalLayout {
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
}
在下面的示例中,另一方面,指定矩形应与布局的起始位置(视觉上的左侧)对齐。 这样就不会拉伸矩形,而是保留其指定的最小宽度:
// 除非指定了对齐方式
export component Example inherits Window {
width: 200px;
height: 200px;
HorizontalLayout {
alignment: start;
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
}
下面的示例嵌套了两个布局以获得更复杂的场景:
export component Example inherits Window {
width: 200px;
height: 200px;
HorizontalLayout {
// 侧面板
Rectangle { background: green; width: 10px; }
VerticalLayout {
padding: 0px;
// 工具栏
Rectangle { background: blue; height: 7px; }
Rectangle {
border-color: red; border-width: 2px;
HorizontalLayout {
Rectangle { border-color: blue; border-width: 2px; }
Rectangle { border-color: green; border-width: 2px; }
}
}
Rectangle {
border-color: orange; border-width: 2px;
HorizontalLayout {
Rectangle { border-color: black; border-width: 2px; }
Rectangle { border-color: pink; border-width: 2px; }
}
}
}
}
}
对齐#
每个元素的大小是根据其 width 或 height 来设定的,如果这些属性被指定了的话。如果没有指定,那么它的大小会被设置为最小尺寸,这个最小尺寸是通过 min-width 或 min-height 属性来设定的,或者是通过内部布局的最小尺寸来设定的,取两者中较大的那个值作为元素的最终大小。
元素根据对齐方式放置。元素的大小只有在布局的 alignment 属性为 LayoutAlignment.stretch(默认值)时才会大于最小尺寸。
这个例子展示了不同的对齐方式:
export component Example inherits Window {
width: 300px;
height: 200px;
VerticalLayout {
HorizontalLayout {
alignment: stretch;
Text { text: "stretch (default)"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
HorizontalLayout {
alignment: start;
Text { text: "start"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
HorizontalLayout {
alignment: end;
Text { text: "end"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
HorizontalLayout {
alignment: start;
Text { text: "start"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
HorizontalLayout {
alignment: center;
Text { text: "center"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
HorizontalLayout {
alignment: space-between;
Text { text: "space-between"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
HorizontalLayout {
alignment: space-around;
Text { text: "space-around"; }
Rectangle { background: blue; min-width: 20px; }
Rectangle { background: yellow; min-width: 30px; }
}
}
}
拉伸算法#
当 alignment 设置为 stretch(默认值)时,元素被调整为其最小尺寸,然后额外的空间按照其拉伸因子进行比例分配,这个拉伸因子是通过 horizontal-stretch 和 vertical-stretch 属性来设定的。拉伸后的大小不会超过最大尺寸。拉伸因子是一个浮点数。那些默认内容大小的元素通常默认为 0,而那些默认为其父元素大小的元素通常默认为 1。
拉伸因子为 0 的元素将保持其最小尺寸,除非所有其他元素的拉伸因子也为 0 或达到其最大尺寸。
例子:
export component Example inherits Window {
width: 300px;
height: 200px;
VerticalLayout {
// Same stretch factor (1 by default): the size is divided equally
HorizontalLayout {
Rectangle { background: blue; }
Rectangle { background: yellow;}
Rectangle { background: green;}
}
// Elements with a bigger min-width are given a bigger size before they expand
HorizontalLayout {
Rectangle { background: cyan; min-width: 100px;}
Rectangle { background: magenta; min-width: 50px;}
Rectangle { background: gold;}
}
// Stretch factor twice as big: grows twice as much
HorizontalLayout {
Rectangle { background: navy; horizontal-stretch: 2;}
Rectangle { background: gray; }
}
// All elements not having a maximum width have a stretch factor of 0 so they grow
HorizontalLayout {
Rectangle { background: red; max-width: 20px; }
Rectangle { background: orange; horizontal-stretch: 0; }
Rectangle { background: pink; horizontal-stretch: 0; }
}
}
}
for#
VerticalLayout 和 HorizontalLayout 也可以包含 for 或 if 表达式:
export component Example inherits Window {
width: 200px;
height: 50px;
HorizontalLayout {
Rectangle { background: green; }
for t in [ "Hello", "World", "!" ] : Text {
text: t;
}
Rectangle { background: blue; }
}
}
网格布局#
网格布局将元素放置在网格中。
每个元素都获得属性 row,col,rowspan 和 colspan。
可以使用 Row 子元素,也可以显式设置 row 属性。
这些属性必须在编译时静态知道,因此不可能使用算术或依赖于属性。截至目前,不允许在网格布局中使用 for 或 if。
这个例子使用 Row 元素
export component Foo inherits Window {
width: 200px;
height: 200px;
GridLayout {
spacing: 5px;
Row {
Rectangle { background: red; }
Rectangle { background: blue; }
}
Row {
Rectangle { background: yellow; }
Rectangle { background: green; }
}
}
}
这个例子使用 row 和 col 属性
export component Foo inherits Window {
width: 200px;
height: 150px;
GridLayout {
spacing: 0px;
Rectangle { background: red; }
Rectangle { background: blue; }
Rectangle { background: yellow; row: 1; }
Rectangle { background: green; }
Rectangle { background: black; col: 2; row: 0; }
}
}