LibGdx 游戏开发之TableLayout
https://github.com/EsotericSoftware/tablelayout
Please use the TableLayout discussion group for support.
Overview 概述
TableLayout
是一个轻量级的Java库,它和HTML的table类似。可以利用logical table
来设置UI widget的位置
和尺寸
。
TableLayout的核心是UI toolkit agnostic
,支持 libgdx, Swing, Android, and TWL。使用table的layout非常直观,而且TableLayout's JAVA API非常好用。
快速开始
下面是libgdx中一个简单例子:
// Keep your code clean by creating widgets separate from layout.
Label nameLabel = new Label("Name:", skin);
TextField nameText = new TextField(skin);
Label addressLabel = new Label("Address:", skin);
TextField addressText = new TextField(skin);
Table table = new Table();
table.add(nameLabel); // Row 0, column 0.
table.add(nameText).width(100); // Row 0, column 1.
table.row(); // Move to next row.
table.add(addressLabel); // Row 1, column 0.
table.add(addressText).width(100); // Row 1, column 1.
上面的代码增加了2行2列一共4个单元格。add
方法返回1个cell
, cell
有控制layout的方法。在例子中text fields的宽度被设置为100.
本文档中使用的示例代码是针对libgdx的,但其他支持的工具包的API几乎完全相同。
Root table 根表
当进行UI布局的时候,UI widget并不设置它自己的尺寸,它只是提供minimun
,preferred
和maximum
三种选项。widget的父元素使用其自身的尺寸和这三种选项,来对widget进行尺寸设置。许多布局会使用单个固定尺寸(通常为整个屏幕)的table作为根表
.widgets和内部表被加入到根表中。
每种UI toolkit都有不同的设定根表尺寸的方法,例如:在Swing中需要把table加入JFrame‘s的内容面板;在libgdx中用setFillParent
方法:
Table table = new Table();
table.setFillParent(true);
stage.addActor(table);
Debugging 调试
TableLayout可以画出调试线,用于视觉化。Debugging通过在table上调用debug
方法来开启。如果debugging开启了,Libgdx可以自动渲染调试线。其他的UI toolkits可能需要调用函数去渲染调试线。
table.debug(); // Turn on all debug lines (table, cell, and widget).
table.debugTable(); // Turn on only table lines.
Adding cells 增加单元格
Widgets通过add
方法来加入到表格(对于已经有add
方法的UI toolkits,那么将使用addcell
方法)。这个方法将在此行中增加1个单元格。如果要增加下一行,则调用row
方法。
table.add(nameLabel); // Row 0, column 0.
table.add(nameText); // Row 0, column 1.
table.row(); // Move to next row.
table.add(addressLabel); // Row 1, column 0.
table.add(addressText); // Row 1, column 1.
add
方法返回一个Cell,Cell有一些属性可以控制布局。Cell的每个方法的返回值都是Cell,允许链式调用。
table.add(nameText).padLeft(10).width(100); // Sets left padding and width on the new cell.
Logical table 逻辑表
这些Cells组成了一个逻辑表
,但是逻辑表的大小和table的尺寸是不一样的。
外面的蓝色矩形展示了table widget的尺寸。里面的蓝色矩形展示了逻辑表的尺寸,且默认居中对齐。对齐方式可以通过table的函数去设置。table
函数反馈值为table,所以也可以像cell的方法一样进行链式调用。
table.right().bottom();
image.png
Cell properties 单元格属性
Expand 扩展
为了使得逻辑表占据table的全部,TableLayber需要被告知那些cells会占用到额外的空间。
table.add(nameLabel).expandX(); // Column 0 receives all extra horizontal space.
table.add(nameText).width(100);
table.row();
table.add(addressLabel);
table.add(addressText).width(100);
image.png
红线表示单元格边界,绿线表示widget的边界。注意左边列占据了X轴上横向空间。只需要有1个单元格被扩展,就可以占用整行或者整列的额外空间。如果多列被扩展,那么额外的空间就会均匀分布。
table.add(nameLabel).expandX(); // Receives extra horizontal space.
table.add(nameText).width(100).expandX(); // Also receives extra horizontal space.
table.row();
table.add(addressLabel);
table.add(addressText).width(100);
image.png
见下图: Expand
在Y轴同样适用,相应函数是expandY
。expand
方法则是在X和Y轴上都进行扩展。
table.add(nameLabel).expand(); // Receives all extra horizontal and vertical space.
table.add(nameText).width(100);
table.row();
table.add(addressLabel);
table.add(addressText).width(100);
image.png
Alignment 对齐
与对齐逻辑表类似,widget在单元格里面也能做对齐。
table.add(nameLabel).expand().bottom().right(); // Aligned bottom right.
table.add(nameText).width(100).top(); // Aligned top.
table.row();
table.add(addressLabel);
table.add(addressText).width(100);
image.png
Fill 填充
fill
方法使得widget的尺寸调整到单元格的尺寸。同expand类似,有fillX
和fillY
两种方法。
table.add(nameLabel).expand().bottom().fillX(); // Sized to cell horizontally.
table.add(nameText).width(100).top();
table.row();
table.add(addressLabel);
table.add(addressText).width(100);
image.png
请注意,红色单元格线是在绿色小部件行的顶部绘制的。
Widget size Widget的尺寸
默认情况下,attempt将widgets的尺寸调整到它们的preferred size
。如果widget不能适配,它们的尺寸将被调整到preferred size
和minimum size
之间,具有较大首选尺寸的小部件,将获得更多空间。
如果widgets的minimum size
都不能使用,那么布局被破坏,widgets可能重叠。 “fill”方法不会使widgets大于widgets的最大尺寸。
不应将Widgets改为preferred
,minimum
或'maximum'。 相反,这些size可以在cell上进行设置,并将用来代替widgets的size。
table.add(nameLabel);
table.add(nameText).minWidth(100); // Sets min width.
table.row();
table.add(addressLabel);
table.add(addressText).prefWidth(999); // Sets pref width.
image.png
这里的“prefWidth”是999,比table还是大,因此它的大小将自动调整`。
width
方法可以快捷的设置 minWidth
, prefWidth
, 和 maxWidth
为相同的值. height
方法可以快捷的设置 minHeight
, prefHeight
, 和 maxHeight
为相同的值. size
方法需要width
和height
,且设置所有6个属性.
Padding 填充
padding
是指单元格边缘的额外空间。
table.add(nameLabel);
table.add(nameText).width(100).padBottom(10); // Sets bottom padding.
table.row();
table.add(addressLabel);
table.add(addressText).width(100).pad(10); // Sets top, left, bottom, right padding.
image.png
请注意:单元格之间的
padding
,所以文本字段之间有20个像素。 调试线不一定显示paddning
来自哪个单元格,因为它对于表格的布局并不重要。填充也可以应用到table的边缘。
table.pad(10);
Spacing
和padding类似,spacing
是cell边的额外空间。但是cells之间的spacing不会联合,相反,较大的一个spacing会被使用。另外,spacing不适用于table. spacing使得cells之间的一致的空间变得容易。
table.add(nameLabel);
table.add(nameText).width(100).spaceBottom(10); // Sets bottom spacing.
table.row();
table.add(addressLabel);
table.add(addressText).width(100).space(10); // Sets top, left, bottom, right spacing.
image.png
注意:cells之间的spacing不会融合,所有在text fildes之间有10 pixels. 另外注意在text field的低部没有spcing,因为spacing不适用于table的边界。
Colspan
一个cell可以span多列(就是合并)。
table.add(nameLabel);
table.add(nameText).width(100).spaceBottom(10);
table.row();
table.add(addressLabel).colspan(2); // Spans 2 columns.
image.png
注意: 不能合并多个行。但是可以用嵌套表格达到此目的。
Uniform 统一
单元格设置uniform
后,单元格的尺寸都变成统一的。
Cells with uniform
set to true will be the same size.
table.add(nameLabel).uniform(); // These two cells will have
table.add(nameText).width(100).uniform(); // the same width and height.
table.row();
table.add(addressLabel);
table.add(addressText).width(100);
image.png
Defaults 默认
Cell defaults 单元格默认
一般来说,单元格设计时一般采用相同的属性,所有给所有单元设置一个默认的属性会大大减少布局的工作量。table的defaults
方法返回一个单元格,这个单元格的属性将被应用到所有的单元格。
table.defaults().width(100); // Sets defaults for all cells.
table.add(nameLabel);
table.add(nameText);
table.row();
table.add(addressLabel);
table.add(addressText);
image.png
Column defaults 列默认
table的columnDefaults
方法返回一个单元格,这个单元格的属性将应用于此单元格所在的列的所有单元格。通过方法设置的属性将覆盖单元格的默认属性。列的索引从0开始。
table.columnDefaults(1).width(150); // Sets defaults for cells in column 0.
table.add(nameLabel);
table.add(nameText);
table.row();
table.add(addressLabel);
table.add(addressText);
image.png
Row defaults 行默认
当row方法调用时,会返回一个单元格,这个单元格的属性将被应用到其所在行的所有单元格。通过此方法设置的属性将会覆盖单元格的默认属性和列的默认属性。row
方法在增加单元格之前就可以调用,这就使得第一行就可以用默认的属性。
table.row().height(50); // Set cell defaults for row 0.
table.add(nameLabel);
table.add(nameText);
table.row().height(100); // Set cell defaults for row 1.
table.add(addressLabel);
table.add(addressText);
image.png
Stacks 堆栈
stack widget是一种特殊类型的容器,它将每个child设置为stack的大小。当需要将widgets堆叠在一起时,这非常有用。 添加到stack的第一个widget绘制在底部,添加的最后一个widget绘制在顶部。
Similar libraries
A few Java, table-based layout managers:
GridBagLayout can handle complex table-based layouts, but does so via a clunky API.
TableLayout (the other one) uses 2D arrays of percentages, sizes, and flags to describe the table and how it should be sized. This approach has the same problems as GridBagLayout.
PageLayout uses a concise Java API to describe the table.
PnutsLayout (webpage no longer available) was written by Toyokazu Tomatsu as part of Pnuts. TableLayout was originally inspired by PnutsLayout.
UIHierarchy was also inspired by PnutsLayout. It is interesting because it is not actually a layout manager, instead it uses a combination of method chaining and constraint strings to more cleanly create UI hierarchies and configure layout parameters.
RiverLayout uses tags in constraint strings.
FormLayout is similar to RiverLayout, but more sophisticated.
MIGLayout is even more sophisticated than FormLayout. It attempts to support many kinds of layouts beyond tables and has a somewhat bloated number of features. It has a complex constraint language. It can layout using a grid, border, absolute, etc.
DesignGridLayout uses canonical grids. For the most part, widgets are simply added and the ideal table is determined automatically. This cuts down the needed Java code to a minimum and enforces UI guidelines. The downside is that DesignGridLayout does not handle arbitrary table layouts. If a UI problem can be handled using a canonical grid, DesignGridLayout is the most elegant solution. If you want to deviate from a canonical grid, you have no recourse.
Please feel free to submit additional libraries to be included in this section or suggest better descriptions.