GridLayout將一個容器的組件放在一個矩形網(wǎng)格中。容器被分成等大小的矩形,每個矩形中放置一個組件霜定。那么GridLayout內(nèi)部的處理邏輯是如何做的呢往堡,下圖是它的幾個核心方法:
GridLayout核心方法
preferredLayoutSize
- 這個方法在布局之前就會調(diào)用來確定大小尺寸.
public Dimension preferredLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
//獲取容器四周內(nèi)間距
Insets insets = parent.getInsets();
//獲取組件數(shù)量
int ncomponents = parent.getComponentCount();
//行
int nrows = rows;
//列
int ncols = cols;
if (nrows > 0) {
//根據(jù)組件數(shù)計算真實需要的行數(shù)
ncols = (ncomponents + nrows - 1) / nrows;
} else {
//根據(jù)組件數(shù)計算真實需要的列數(shù)
nrows = (ncomponents + ncols - 1) / ncols;
}
//寬
int w = 0;
//高
int h = 0;
for (int i = 0; i < ncomponents; i++) {
//遍歷組件
Component comp = parent.getComponent(i);
//獲取預(yù)設(shè)尺寸大小
Dimension d = comp.getPreferredSize();
//記錄行寬(以最寬的組件作為平均格子寬度)
if (w < d.width) {
w = d.width;
}
//記錄行高(以最高的組件作為平均格子高度)
if (h < d.height) {
h = d.height;
}
}
//根據(jù)記錄的寬高加上盒子內(nèi)間距和組件之間的間隙計算出容器的尺寸大小
return new Dimension(insets.left + insets.right + ncols * w + (ncols - 1) * hgap,
insets.top + insets.bottom + nrows * h + (nrows - 1) * vgap);
}
}
minimumLayoutSize
- 這個方法用途是在計算布局所需的最小尺寸大小
public Dimension minimumLayoutSize(Container parent) {
synchronized (parent.getTreeLock()) {
//獲取容器四周內(nèi)間距
Insets insets = parent.getInsets();
//獲取組件數(shù)量
int ncomponents = parent.getComponentCount();
//行
int nrows = rows;
//列
int ncols = cols;
if (nrows > 0) {
//根據(jù)組件數(shù)計算真實需要的行數(shù)
ncols = (ncomponents + nrows - 1) / nrows;
} else {
//根據(jù)組件數(shù)計算真實需要的列數(shù)
nrows = (ncomponents + ncols - 1) / ncols;
}
//寬
int w = 0;
//高
int h = 0;
for (int i = 0; i < ncomponents; i++) {
//遍歷組件
Component comp = parent.getComponent(i);
//獲取組件的最小尺寸
Dimension d = comp.getMinimumSize();
//記錄行寬(以最寬的組件作為平均格子寬度)
if (w < d.width) {
w = d.width;
}
//記錄行高(以最高的組件作為平均格子高度)
if (h < d.height) {
h = d.height;
}
}
//根據(jù)記錄的寬高加上盒子內(nèi)間距和組件之間的間隙計算出容器的尺寸大小
return new Dimension(insets.left + insets.right + ncols * w + (ncols - 1) * hgap,
insets.top + insets.bottom + nrows * h + (nrows - 1) * vgap);
}
}
layoutContainer
- 這個方法和Android中的onLayout方法很相似男摧,因為它也是在父類Container也是onLayout方法中調(diào)用的。
public void layoutContainer(Container parent) {
synchronized (parent.getTreeLock()) {
//獲取容器四周內(nèi)間距
Insets insets = parent.getInsets();
//獲取組件數(shù)量
int ncomponents = parent.getComponentCount();
//行
int nrows = rows;
//列
int ncols = cols;
//是否是LTR模式
boolean ltr = parent.getComponentOrientation().isLeftToRight();
//如果沒有組件的話直接結(jié)束布局
if (ncomponents == 0) {
return;
}
if (nrows > 0) {
//根據(jù)組件數(shù)計算真實需要的行數(shù)
ncols = (ncomponents + nrows - 1) / nrows;
} else {
//根據(jù)組件數(shù)計算真實需要的列數(shù)
nrows = (ncomponents + ncols - 1) / ncols;
}
// To position components in the center we should:
// 1. get an amount of extra space within Container
// 2. incorporate half of that value to the left/top position
// Note that we use trancating division for widthOnComponent
// The reminder goes to extraWidthAvailable
// 為了將組件放置在中間我們需要做:
// 1. 從容器中獲得一片額外空間
// 2. 將該值的一半合并到左上角
// extraWidthAvailable的值是對widthOnComponent使用了轉(zhuǎn)移除法得到的
// 計算水平間隙總寬度
int totalGapsWidth = (ncols - 1) * hgap;
// 計算容器除去左右內(nèi)間距的可用寬度
int widthWOInsets = parent.width - (insets.left + insets.right);
// 計算留給組件的寬度(可用寬度-總間隙寬度)/組件數(shù)量
int widthOnComponent = (widthWOInsets - totalGapsWidth) / ncols;
// 計算額外的可用寬度值用于居中使用(然鵝值為0 :-D)
// widthOnComponent * ncols = widthWOInsets - totalGapsWidth;
// widthWOInsets - (widthWOInsets - totalGapsWidth + totalGapsWidth) = 0
// extraWidthAvailable = 0;
int extraWidthAvailable = (widthWOInsets - (widthOnComponent * ncols + totalGapsWidth)) / 2;
// 計算垂直間隙的總高度
int totalGapsHeight = (nrows - 1) * vgap;
// 計算容器除去左右內(nèi)間距的可用高度
int heightWOInsets = parent.height - (insets.top + insets.bottom);
// 計算留給組件的高度(可用高度-總間隙寬度)/組件數(shù)量
int heightOnComponent = (heightWOInsets - totalGapsHeight) / nrows;
//計算額外的可用高度值用于居中使用(然鵝值為0 :-D) 推理同extraWidthAvailable
int extraHeightAvailable = (heightWOInsets - (heightOnComponent * nrows + totalGapsHeight)) / 2;
//根據(jù)布局模式分兩種情況討論
// c代表行 r代表列 x橫坐標(biāo) y縱坐標(biāo)
// 每次計算相對應(yīng)的x和y坐標(biāo)值
// LTR: 第一個組件需要加上左上內(nèi)間距值(x = insets.left + extraWidthAvailable, y = insets.top + extraHeightAvailable)
// RTL: 第一個組件需要加上上內(nèi)間距減去右內(nèi)間距(x = (parent.width - insets.right - widthOnComponent),insets.top + extraHeightAvailable)
if (ltr) {
for (int c = 0, x = insets.left + extraWidthAvailable; c < ncols; c++, x += widthOnComponent + hgap) {
for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows; r++, y += heightOnComponent + vgap) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
}
}
}
} else {
for (int c = 0, x = (parent.width - insets.right - widthOnComponent) - extraWidthAvailable; c < ncols; c++, x -= widthOnComponent + hgap) {
for (int r = 0, y = insets.top + extraHeightAvailable; r < nrows; r++, y += heightOnComponent + vgap) {
int i = r * ncols + c;
if (i < ncomponents) {
parent.getComponent(i).setBounds(x, y, widthOnComponent, heightOnComponent);
}
}
}
}
}
}