一、了解箱子布局
箱子布局是一种新颖的布局方式,其布局模型可以更好地优化UI设计的工作。它率先在 XUL 界面语言中被提出,广泛应用于 Mozilla 的应用程序,如 FireFox 等等。在 CSS 布局系统中(for CSS v3),作为新增的补充形式,箱子布局可以指定子元素在水平或垂直的任意一种方向进行排列,剩下有多的空间由已声明了的子元素来填空(声明 flex 项)。
我们知道,在 Ext JS 中,容器里面是用来放置组件的,至于容器内的子组件怎么排列就由布局风格来指定。3.0 提供了新的基于箱子模型的布局方式,分别是 Hbox 和 Vbox,对应的命名空间是 Ext.layout.HBoxLayout 和 Ext.layout.VBoxLayout。HBox 全称 Horizontal Box,其中所有子项都是自动按顺序横排。VBox 则相反,全称 Vertical Box,里面为竖排方式。所谓箱子模型的意思,就是将显示部分分割成一系列的 box,按照水平的或垂直的两种方位排列组织。水平 box 可以将其子组件排成一条线,而垂直 box 可以将其子组件定位成垂直方向。如果既然要水平方向和垂直方向两个方向填充内容,我们可以相互内嵌布局,即水平布局内嵌垂直布局,或垂直布局内嵌水平布局。
透过下图的一个例子可以看到两种方向的不同。
箱子模型的理论其实很人性化,既可以支持固定值尺寸的子项内容,也可以支持自适应的子项。箱子布局中的元素可以分配一个固定的值,也有可能加大尺码,这是容器空间有余的情况;另一种情况,则是容器空间不够容纳元素,就缩小某个元素的尺寸以适应。作用在那个元素身上?有 flex 配置项的子项元素,也就是说,HBox/VBox 布局会把有设定 flex 配置的子项划分垂直或水平的空间。另外,容器中元素的位置和顺序也会某程度地改变。
二、API攻略
a.flex 配置项
flex 配置项不是设置在布局上,而是设置在子项的配置项。每个子项相对的 flex 值都会与全体子项 flex 累加的值相比较,根据此结果,处理每个子项的 flex 最后是多少。若不设置子项的 flex,表示不对子项作自适应尺寸的处理,相当于 flex = 0 的子项或 flex = undefined 的时候,表示子项不会自伸缩处理,而采用最初的尺寸。
如下例:
{
layoutConfig: {
padding:'5',
align:'top'
},
defaults:{margins:'0 5 0 0'},
items:[{
xtype:'button',
text: 'Button 1',
flex:1
},{
xtype:'button',
text: 'Button 2',
flex:1
},{
xtype:'button',
text: 'Button 3',
flex:1
},{
xtype:'button',
text: 'Button 4',
flex:3,
margins:'0'
}]
}
该配置项效果如下图:
如果子项都设置相同 flex 值,那就意味着全体子项作相同的处理。
技巧:我们可以只让一个 panel 设定 flex,便可以作为填充空白的 spacer:
{
layoutConfig: {
padding:'5',
align:'top'
},
defaults:{margins:'0 5 0 0'},
items:[{
xtype:'button',
text: 'Button 1'
},{
xtype:'spacer',
flex:1
},{
xtype:'button',
text: 'Button 2'
},{
xtype:'button',
text: 'Button 3'
},{
xtype:'button',
text: 'Button 4',
margins:'0'
}]
} 效果如下:
flex 的文档也不是说得太清楚,不过我们可以多参考官方例子是怎么使用 flex 的。一旦你明白了flex 这个概念之后,它会非常灵活地进行布局。
b.如何对齐 align & pack
当然我们可以 Vbox 布局中内嵌 hbox 布局,或者 hbox 中内嵌 vbox,HBox 和 VBox 之间是可以允许嵌套布局的,但实际不必如此手动去做, Ext JS 为我们提供了“对齐 align/pack”的这一对方向各异的调整配置,代替了上述“内嵌”的这一种稍微让人感觉别扭。容器中每一个子项都遵循用户指定的 align/pack 对齐方式。一般设置的地方是在容器的 layoutConfig 配置项对象中,如下面某一个容器的代码片断:
layout:'hbox',
layoutConfig: {
align : 'stretch',
pack : 'start',
},
items: [
{html:'panel 1', flex:1},
{html:'panel 2', width:150},
{html:'panel 3', flex:2}
]
对于垂直布局的 VBox 而言,属性 align 就是水平对齐的设置了,align 有以下可选项:
键值 | 作用 |
left | 居左,从容器的 left 开始水平对齐。这是系统默认的选项。 |
center | 居中,从容器的 mid-width 开始垂直对齐。 |
stretcn | 拉伸子项以填充容器的水平宽度。 |
stretcnmax | 拿最宽的那个子项拉伸,适应容器的水平宽度。 |
属性 pack 是控制容器里面的子项是如何停靠的,这是垂直方向本身的对齐。有如以下设置:
键值 | 作用 |
start | 居顶,从容器的 top 停靠子项。这是系统默认的选项。 |
center | 居中,也就是子项都从容器的 mid-height 上开始停靠。 |
end | 居底,从容器的底部边边开始往上摆子组件。 |
对于水平布局的 HBox 而言,align 就是决定如何垂直对齐,align 的可选项有如下:
键值 | 作用 |
top | 顶部对齐,从容器的 top 开始垂直对齐。 |
middle | 居中对齐,从容器的 middle 开始垂直对齐。 |
stretch | 拉伸子项以填充容器的垂直高度。 |
stretchmax | 拿最高的那个子项拉伸,适应容器的垂直高度。 |
pack的可选项有以下几种:
键值 | 作用 |
start | 居左,从左边开始排列内容。 |
center | 居中,也就是从容器的 mid-width 开始停靠内容。 |
end | 居右,从容器的右边开始停靠内容。 |
对于 top、middle/center 我们能够一眼地看出是什么意思,而 stretch/stretchmax 又是什么用法呢?一图胜千言,我们看看下面这张图(点击图片运行例子以了解更多的适用情形):
c.设置内外边距
BoxLayout 可设置外边距(margins)。关于 defaultMargins,就是如果不制定每个子项的 margins 属性,那么就会使用默认的 margins。规定 defaultMargins 的格式如下:
{
top: (top margin),
right: (right margin),
bottom: (bottom margin),
left: (left margin)
}
默认为 {top:0, right:0, bottom:0, left:0} 。margin 属性接纳的格式也可以是字符串的,规定为空格隔开,数字类型的 margin 值。各个方向的排列顺序为 CSS 的顺序:
- 如果只是一个值,就是各个方向都是这个值。
- 如果有两个值,那么第一个值代表是上下方向的值,第二值则是左右方向的值。
- 如果有三个值,第一个值是顶部的值,第二个值是左右两边的值,第三个值是底部的值。
- 如果有四个值,分别代表就是顶部、右边、底部和左边的值(为方便记忆,可理解为顺时针方向)。
BoxLayout 可设置内边距(padding)。跟 defaultMargins 差不多,padding 属性接纳的格式也可以是字符串的,其格式规定为空格隔开,数字类型的 margin 值。各个方向的排列顺序为 CSS 的顺序。
三、小结
需要说明的是,H & V 箱子模型只限特定的应用场合使用,不是在任何布局都可适应。例如,H & V BoxLayout 就不支持渲染表单的 fieldLabels。要解决此问题,可以为 fieldLables 增加一层 layout:'form' 的容器。尽管理论上可设计一个满足多样需求的布局,但性能会是一大障碍(可参阅 http: //www.extjs.com/forum/showthread.php?p=396565#post396565)。也可以使用其他的布局风格,如 TableLayout 代替,但 TableLayout 一个明显的不足是其子项的增、删、改都不太方便;再如浮动布局 FloatLayout,FloatLayout 很像水平布局的 HBoxLayout,支持 x/y 的绝对布局,不过就没有自适应大小的功能。如果没有大小尺寸不够放得下,就换行显示。FloatLayout 同样有拉伸子项的功能,也支持 top/bottom/middle 对齐,以及居中、居左、居右的功能。
可见,H & V BoxLayout 越来越备受推崇,必须把它弄懂才行。学习游泳最好的方法就是跳进水里大胆试试,把上面的例子和官方源码当作你的湖吧!
四、延伸阅读:
- 运行布局浏览器
- W3C 的Flexible Box文档
- VBox/HBox 汉化文档
- Grid 如何高/宽自适应
- Flex 布局没有滚动条?