文档中心

控件开发_自动布局和配置文件

03.控件的自动布局

控件的布局文件中指定的位置和大小信息都是创建时的初始布局信息。要求当父控件的大小发生变化时,子控件的布局能够自动调节,使得界面显示更合理。
假如有一个初始的竖屏界面如下

要求 gray窗口的大小发生变化时:green窗口的左边间距保持 10个点,green窗口和 red窗口之间保持 10个点,red窗口的右边间距 10个点,然后 green窗口和 red 窗口的宽平分剩下的水平空间;垂直方向上 green窗口和 red窗口的上边和下边都对齐,上边距 20个点,下边正好到 gray窗口高的一半(50%)。blue窗口左边要和 green窗口对齐,右边要和 red窗口对齐,并且 green窗口的上边和下边间距都是 10个点。当gray窗口变成横屏时,仍然满足上述条件,布局自动调整为:

传统的基于固定位置或比例的自动布局方式已经不能满足这么灵活的要求。TD图形软件系统控件系统发明了一种方法,把用户的这些布局要求转换成简单数学公式描述的约束条件,并能够快速高效的执行这些约束条件,完成自动布局。先介绍约束条件中用到的几个布局属性(x,y,w,h,r,b):

如上图,子控件的(w, h)表示它的宽高,子控件的 x表示它右边缘的位置(相对于父窗口左边),子控件的 r表示它右边缘的位置(也是相对于父窗口左边),显然 r等于(x+w)。子控件的 y表示它上边缘的位置(相对于父窗口上边),子控件的 b表示它下边缘的位置(也是相对于父窗口上边),显然 b等于(y+h)。这些属性都以像素为单位。

开发者关于布局的要求都可以转换成基于这些布局属性的数学公式。比如上面例子中的布局要求:

布局要求

约束公式

green窗口的左边间距是 10个点,

green窗口和 red窗口之间有 10个点,

red窗口的右边间距 10个点,

green窗口和 red窗口的宽平分剩下的水平空间

green.w = gray.w * 50% - 15

green.x = 10

red.x = green.r + 10

red.r = gray.w - 10 或 red.w = green.w

green窗口和 red窗口的上边和下边都对齐,上边

距20个点,下边正好到 gray窗口高的一半(50%)

green.y = 20

red.y = green.y

green.h = gray.h * 50% - 20  red.h = green.h

blue窗口左边要和 green窗口对齐,

右边要和 red窗口对齐,

green窗口的上边和下边间距都是 10个点

blue.x = green.x

blue.r = red.r

blue.y = green.b + 10

blue.b = gray.h - 10

reen.w = (graw.w - 10 - 10 - 10) * 50% = gray.w * 50% - 15。把计算green.w的约束放在前面,因为控件系统是按顺序来执行约束公式的,下面计算 red.x时 要用到 green.r,而 green.r等于(green.x+green.w)。

把布局约束加入到布局文件中:

gray = {
type=id("window")
x=0; y=0; w=200; h=300
green = {
    type=id("window")
    x=10; y=20; w=85; h=130
}
red = {
    type=id("window")
    x=105; y=20; w=85; h=130
}
blue = {
    type=id("window")
    x=10; y=160; w=180; h=130
}
layout=“
    green.w = [parent].w * 50% - 15
    green.h = [parent].h * 50% - 20
    red.x = green.r + 10
    red.w = green.w
    red.h = green.h
    blue.x = green.x
    blue.r = red.r
    blue.y = green.b + 10
    blue.b = [parent].h - 10“
}

布局约束是作为父窗口的一个字符串属性(layout)加入的,在上例中去掉了一些常量的赋值约束比如 green.x=10和 green.y = 20,因为创建 green控件时它的 x等于10、y等于 20,如果没有约束改变 green.x和 green.y,那么它们就保持不变。

还做了一个改动就是用[parent]来表示父窗口 gray。

目前只有窗口控件支持子控件自动布局,并且支持下面四种布局约束表达式:

name.item = ref_name.item * scale +offset

赋值约束

name.item >= ref_name.item * scale+ offset

最小值约束

name.item <= ref_name.item * scale + offset

最大值约束

name.item ^= ref_name.item * scale + offset

居中约束

其中 name是子控件的名字,ref_name是参考控件的名字,ref_name有下面三种形式:

1、兄弟控件的名字;(父控件相同的是兄弟控件)

2、父窗口,用[parent]表示;([parent].x[parent].y等于 0

3、自身,用[self]表示;

item就是 x,y,w,h,r,b中的一个。

scale是一个十进制的整数、小数或百分数,比如 2、1.5、50%、30.5%。如果 scale为 1,可以不写 scale,即只写 ref_name.item+offset,如果 scale为 0,可以只有 offset。

offset是一个十进制的整数或小数。如果 offset为 0,可以不写 offset。

在居中约束中,name.item中的 item只能是 w或 h,表示控件的宽或高相对于其他控件是居中的(中间对齐),居中约束只修改 name.x或 name.y来达到。

在前三种约束中,name.item中的 item如果为 x或 r其实是指明了 name控件左边缘或右边缘的位置。但是满足 r的约束条件可以通过改变 x来达到,也可以通过改变 w来达到,如下面二图所示,图 A是通过修改 red.x来满足 red.r的约束,图 B中是通过改变red.w来满足 red.r的约束,因为之前有 red.x的约束,所以应该维持 red.x不变才是合理 的。

                           图 A                                                                    图 B

当然也会有冲突的情况,如果前面同时有或者同时没有 red.x和 red.w的约束,然后遇到 red.r的约束,无法确定修改对象。应尽量不改变控件的大小来满足约束,即只修改 red.x。

下表列出了在各种情况下的合理规则:

约束表达式

不同情况

规则

name.r = ....

之前有 name.x的约束,没有 name.w的约束

改变 name.w

其他

改变 name.x

name.x = ...

之前有 name.r的约束,没有 name.w的约束

改变 name.x,同时改变

name.w 使 得 name.r 不变

其他

只修改 name.x

name.w = ...

之前有 name.r的约束,没有 name.x的约束

改变 name.w,同时改变

name.x使得 name.r不 变

其他

只修改 name.w

name.item中的 item为 y,b,w的情况类似于上表。