初衷和項(xiàng)目源代碼
主要是解決:同一份數(shù)據(jù),可以動(dòng)態(tài)切換不同的布局
风秤。如果模型數(shù)據(jù)很多條,那么就肯定用UITtableview
妻顶。
原理
MyGirdeLayout->柵格布局:
樹(shù)形結(jié)構(gòu)
UIView.subviews->子視圖:
平面結(jié)構(gòu)
柵格布局:
- 將一個(gè)矩形的視圖區(qū)域按行或者按列的方式劃分為
多個(gè)子區(qū)域
,子區(qū)域根據(jù)布局的要求可以繼續(xù)遞歸劃分
致盟。柵格布局里面的子視圖
將按照添加的順序依次填充到對(duì)應(yīng)的葉子區(qū)域中去的布局方式
薪前。 - 通過(guò)
一套自定義的布局體系來(lái)劃分位置和尺寸
,添加到柵格布局里面的子視圖將不再需要指定位置和尺寸
而是由柵格布局中的子?xùn)鸥駚?lái)完成
,因此可以很很方便的調(diào)整布局結(jié)構(gòu),從而實(shí)現(xiàn)動(dòng)態(tài)布局的能力贝乎。 所謂柵格其實(shí)就是一個(gè)矩形區(qū)域
,我們知道一個(gè)視圖其實(shí)就是一個(gè)矩形區(qū)域,而子視圖的frame屬性其實(shí)就是父視圖中的某個(gè)特定的子區(qū)域部分
宋光。 - 既然子視圖最終占據(jù)的是父視圖的某個(gè)子矩形區(qū)域貌矿。那么我們也可以先將
一個(gè)矩形區(qū)域按照某種規(guī)則分解為多個(gè)子矩形區(qū)域
,然后再將子視圖填充到對(duì)應(yīng)的子矩形區(qū)域中去
,這就是柵格布局的實(shí)現(xiàn)思想
。
葉子格子和非葉子格子區(qū)別
葉子格子
表示里面沒(méi)有子格子而非葉子格子
表示里面有子格子非葉子?xùn)鸥?/code>只能設(shè)置一個(gè)方向的妥锛眩靠,具體只能設(shè)置左中右或者上中下
葉子?xùn)鸥?/code>如果設(shè)置了gravity則填充的子視圖必須要設(shè)置明確的尺寸
視圖組
- 原理
-
數(shù)據(jù)
{"size":"fill","cols":[{"size":"50%","padding":"{0,5,0,5}","right- borderline":{"head":1,"tail":1,"offset":1,"thick"1,"color":"#EEEEEE"}, "bottom-borderline":{"head":1,"tail":1,"offset":1,"thick":1, "color":"#EEEEEE"},"tag":1003,"action":"handleTap:","rows": [{"size":"fill","cols":[{"size":"fill","rows":[{"size":"wrap"}, {"size":"wrap"},{"padding":"{5, 5, 5, 5}","size":"wrap"}]}, {"padding":"{5, 5, 5, 5}","size":"fill"}]}]}
-
視圖
NSMutableArray *temp = [NSMutableArray array]; UIImageView *backgroudImageView = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"bk1"]]; [temp addObject:backgroudImageView]; UILabel *titleLabel = [UILabel new]; titleLabel.text = @"南京精選"; titleLabel.font = [CFTool font:13]; titleLabel.textColor = UIColor.whiteColor; titleLabel.textAlignment = NSTextAlignmentCenter; titleLabel.adjustsFontSizeToFitWidth = YES; [temp addObject:titleLabel]; UILabel *subTitleLabel = [UILabel new]; subTitleLabel.text = @"天貓超市"; subTitleLabel.font = [CFTool font:11]; subTitleLabel.textColor = UIColor.whiteColor; subTitleLabel.textAlignment = NSTextAlignmentCenter; subTitleLabel.adjustsFontSizeToFitWidth = YES; [temp addObject:subTitleLabel]; NSArray *titles = @[@"周末瘋狂趴",@"送5升菜籽油"]; for (NSString *title in titles) { UILabel *lb = [UILabel new]; lb.text = title; lb.font = [CFTool font:12]; lb.textColor = UIColor.redColor; lb.adjustsFontSizeToFitWidth = YES; [temp addObject:lb]; } NSArray *imageNames = @[@"p1-31",@"p1-32"]; for (NSString *imageName in imageNames) { UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:imageName]]; [temp addObject:imageView]; } UIImageView *optionalView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"p1-12"]]; [temp addObject:optionalView]; [self.rootLayout addViewGroup:temp withActionData:@"aa" to:sPartTag3];
這樣就可以根據(jù)數(shù)據(jù)的
Tag
來(lái)指定標(biāo)簽內(nèi)才會(huì)放置綁定的視圖組
逛漫。
布局技巧
拆分子格子幾種方法
描述
- 把格子拆分為2個(gè)行子格子,然后第2個(gè)行子格子拆分為2個(gè)列子格子。
- 因此按照這個(gè)結(jié)構(gòu),我們就可以將那些不重疊排列的x布局按格子布局劃分出來(lái)赘艳。最終所有子視圖都將放在葉子格子里面,而子視圖的放置順序,就是按格子這棵樹(shù)的深度遍歷順序來(lái)存放的酌毡。
- 葉子格子代表里面沒(méi)有子格子,比如這個(gè)格子里面,格子1和格子2.1,2.2都是葉格子。但是格子2和根格子不是葉子格子,這樣如果布局中有3個(gè)子視圖,那么將按照格子的布局順序逐步添加對(duì)應(yīng)的視圖蕾管。
- 例如 視圖1 -> 填充1區(qū)域格子,視圖2 -> 填充2.1區(qū)域格子,視圖3 -> 填充2.2區(qū)域格子枷踏。
-
明確指定高度的
,比如第一個(gè)行子格子的高度時(shí)20。那么就會(huì)建立一個(gè)高度為20,寬度為100的行子格子 -
明確指定高度比例
,比如第二個(gè)行子格子的高度時(shí)整體高度的30%掰曾。那么久會(huì)建立一個(gè)高度為30,寬度為100的行子格子 -
明確指定生于高度比例
,比如第三個(gè)行格子的高度是剩余高度的40%,那么就會(huì)建立一個(gè)(100-20-30) * 0.4 = 20 高度并且寬度為100的行格子 -
明確指定剩余下的所有高度
,比如第四個(gè)行子格子的高度時(shí)剩余下的所有高度,那么就會(huì)建立一個(gè)高度為30,寬度為100的子格子
案例
- 建立三個(gè)高度分別為33.3333%的行子格子
* [grid addRow:1.0/3];
* [grid addRow:1.0/3];
* [grid addRow:1.0/3];
- 建立一個(gè)高度為剩余33.3333%的行格子,第二個(gè)高度為剩余高度50%的行格子,第三個(gè)為剩余全高度的行格子
* [grid addRow:-1.0/3];
* [grid addRow:-1.0/2];
* [grid addRow:MyLayoutSize.fill];
- 建立3個(gè)為剩余全高度的行格子
* [grid addRow:MyLayoutSize.fill];
* [grid addRow:MyLayoutSize.fill];
* [grid addRow:MyLayoutSize.fill];
- 建立為JSON形式
* grid.gridDictionary = @{"rows":[{"size":"33.33%"}旭蠕, {"size":"33.33%"}, {"size":"33.33%"}}]}
* grid.gridDictionary = @{"rows":[{"size":"-33.33%"}, {"size":"-50%"}, {"size":"fill"}]}
* grid.gridDictionary = @{"rows":[{"size":"fill"},{"size":"fill"},{"size":"fill"}]};
這里面可見(jiàn):第一種和第二種都需要指定一個(gè)除不盡的小數(shù)
;但是第三種和第四種就不需要指定任何小數(shù)
布局尺寸描述
@{kMyGridSize:@(20)}
表示尺寸是20
@{kMyGridSize:@"50%"}
表示尺寸是總體的50%
@{kMyGridSize:@"-50%"}
表示是剩余的50%
@{kMyGridSize:vMyGridSizeWrap}
表示尺寸由子格子包裹
@{kMyGridSize:vMyGridSizeFill}
表示尺寸均分和填充剩余的高度或者寬度
anchor錨點(diǎn)
用于柵格
,表示設(shè)置為YES時(shí),柵格也放入一個(gè)對(duì)應(yīng)的子視圖
placeholder
用于葉子?xùn)鸥?/code>,表示設(shè)置為YES時(shí),葉子?xùn)鸥癫粫?huì)放入一個(gè)對(duì)應(yīng)的子視圖
視圖重疊

JSON描述
{
"overlap":"bottom|left",
"padding":"{0,0,5,0}"
}
內(nèi)部實(shí)現(xiàn)
MyGravity tempGravity = MyGravity_None;
NSArray *array = [overlap componentsSeparatedByString:@"|"];
for (NSString *temp in array) {
tempGravity |= [self returnGravity:temp];
}
if (tempGravity != MyGravity_None){
gridNode.anchor = true;
gridNode.measure = 0;
gridNode.gravity = tempGravity;
gridNode.overlap = tempGravity;
}
內(nèi)部機(jī)制三部曲
"gravity":"bottom|left"
表示內(nèi)部視圖尺寸包裹
也就是wrap的簡(jiǎn)寫(xiě)方式
目的是為了減少對(duì)視圖的尺寸設(shè)置
關(guān)鍵一點(diǎn)是必須讓視圖自己包裹展示,而不是設(shè)置尺寸
。否則就達(dá)不到重疊視圖的效果-
anchor:true
柵格放入一個(gè)視圖
-
gravity:
表示重疊時(shí)對(duì)齊方式
注意事項(xiàng)
- 當(dāng)
"overlap":"top|left"
時(shí):表示視圖的頂部對(duì)齊,也就是視圖區(qū)域的底部,然后再往下延伸 - 當(dāng)
"overlap":"bottom|left"時(shí):
表示視圖的底部對(duì)齊,也就是視圖區(qū)域的底部,然后再往上延伸 - 如果想把
千奈美
設(shè)置為左上方
方式:
- 將高度為0的柵格作為第一行,然后再設(shè)置
gravity = top|left
,這種會(huì)造成添加的視圖會(huì)蓋住前面添加的視圖
- 建立一個(gè)子?xùn)鸥?code>推薦這一種
布局屬性介紹
MyGrid
定義格式化柵格描述語(yǔ)言的key和對(duì)應(yīng)的value
- 這些值可以用來(lái)設(shè)置柵格布局的gridDictionary屬性中字典的各種鍵值對(duì)
kMyGridTag: NSNumber類型,設(shè)置柵格的標(biāo)簽,對(duì)應(yīng)MyGrid的tag屬性旷坦。具體值為NSInteger
kMyGridAction: NSString類型掏熬,設(shè)置柵格的觸摸動(dòng)作,對(duì)應(yīng)MyGrid的setTarget中的action參數(shù)
kMyGridActionData: id類型,設(shè)置柵格的動(dòng)作數(shù)據(jù),對(duì)應(yīng)MyGrid的actionData屬性
kMyGridRows: NSArray<NSDictionary>類型,表示里面的值是行子?xùn)鸥駭?shù)組秒梅。數(shù)組的元素是一個(gè)個(gè)子?xùn)鸥褡值鋵?duì)象
kMyGridCols: NSArray<NSDictionary>類型,表示里面的值是列子?xùn)鸥駭?shù)組旗芬。數(shù)組的元素是一個(gè)個(gè)子?xùn)鸥褡值鋵?duì)象
kMyGridSize: NSString類型或者NSNumber類型。設(shè)置柵格的尺寸,可以為特定的值vMyGridSizeWrap或者vMyGridSizeFill,也可以為某個(gè)具體的數(shù)字比如20.0,還可以為百分比數(shù)字比如:@"20%" 或者@"-20%"
kMyGridPadding: NSString類型,設(shè)置柵格的內(nèi)邊距,對(duì)應(yīng)MyGrid的padding屬性,具體的值的格式為:@"{上,左,下,右}"
kMyGridSpace: NSNumber類型番电,柵格的內(nèi)子?xùn)鸥竦拈g距岗屏,對(duì)應(yīng)MyGrid的subviewSpace屬性
kMyGridGravity: NSString類型,柵格的停靠屬性,對(duì)應(yīng)MyGrid的gravity屬性,具體的值請(qǐng)參考下面的定義,比如:@"top|left"
kMyGridPlaceholder://NSNumber類型,柵格的占位屬性,對(duì)應(yīng)MyGrid的placeholder 屬性,具體的值設(shè)置為YES or NO
kMyGridAnchor: NSNumber類型漱办,柵格的錨點(diǎn)屬性,對(duì)應(yīng)MyGrid的anchor屬性婉烟,具體的值設(shè)置為YES or NO
kMyGridTopBorderline: NSDictionary類型 柵格的頂部邊界線對(duì)象
kMyGridBottomBorderline: NSDictionary類型 柵格的底部邊界線對(duì)象
kMyGridLeftBorderline: NSDictionary類型 柵格的左邊邊界線對(duì)象
kMyGridRightBorderline: NSDictionary類型 柵格的右邊邊界線對(duì)象
- 柵格的邊界線對(duì)象所能設(shè)置的key
kMyGridBorderlineColor: NSString類型娩井,用字符串格式描述的顏色值。具體為:@"#FF0000" 表示紅色
kMyGridBorderlineThick: NSNumber類型,邊界線的粗細(xì)
kMyGridBorderlineHeadIndent: NSNumber類型,邊界線的頭部縮進(jìn)值
kMyGridBorderlineTailIndent: NSNumber類型,邊界線的尾部縮進(jìn)值
kMyGridBorderlineOffset: NSNumber類型,邊界線的偏移值
kMyGridBorderlineDash: NSNumber類型,邊界線是虛線
- kMyGridSize可以設(shè)置的特殊值
vMyGridSizeWrap: 表示尺寸由子?xùn)鸥駴Q定
vMyGridSizeFill: 表示尺寸填充父柵格的剩余部分
- kMyGridGravity可以設(shè)置的值
vMyGridGravityTop: 視圖頂部對(duì)齊對(duì)應(yīng)MyGravity_Vert_Top
vMyGridGravityBottom: 視圖底部對(duì)齊對(duì)應(yīng)MyGravity_Vert_Bottom
vMyGridGravityLeft: 視圖左邊對(duì)齊對(duì)應(yīng)MyGravity_Horz_Left
vMyGridGravityRight: 視圖右邊對(duì)齊對(duì)應(yīng)MyGravity_Horz_Right
vMyGridGravityLeading: 視圖頭部對(duì)應(yīng)MyGravity_Horz_Leading
vMyGridGravityTrailing: 視圖尾部對(duì)應(yīng)MyGravity_Horz_Trailing
vMyGridGravityCenterX: 視圖橫行居中MyGravity_Horz_CenterX
vMyGridGravityCenterY: 視圖縱向居中MyGravity_Vert_CenterY
vMyGridGravityWidthFill: 視圖寬度填充MyGravity_Horz_Fill
vMyGridGravityHeightFill: 視圖高度填充MyGravity_Vert_Fill
柵格動(dòng)作接口,您可以觸摸柵格來(lái)執(zhí)行特定的動(dòng)作和事件
/**
柵格動(dòng)作接口似袁,您可以觸摸柵格來(lái)執(zhí)行特定的動(dòng)作和事件洞辣。
*/
@protocol MyGridAction<NSObject>
/**
柵格的標(biāo)簽標(biāo)識(shí)咐刨,用于在事件中區(qū)分柵格。
*/
@property(nonatomic) NSInteger tag;
/**
柵格的動(dòng)作數(shù)據(jù)扬霜,這個(gè)數(shù)據(jù)是柵格的擴(kuò)展數(shù)據(jù)定鸟,您可以在動(dòng)作中使用這個(gè)附加的數(shù)據(jù)來(lái)進(jìn)行一系列操作。他可以是一個(gè)數(shù)值著瓶,也可以是個(gè)字符串联予,甚至可以是一段JS腳本。
*/
@property(nonatomic, strong) id actionData;
/**
設(shè)置柵格的事件,如果取消柵格事件則設(shè)置target為nil
@param target action事件的調(diào)用者
@param action action事件材原,格式為:-(void)handle:(id<MyGrid>)sender
*/
-(void)setTarget:(id)target action:(SEL)action;
@end
柵格協(xié)議:用來(lái)描述柵格塊以及柵格的添加和刪除
柵格可以按某個(gè)方向拆分為眾多子?xùn)鸥?而且這個(gè)過(guò)程可以遞歸進(jìn)行沸久。所有柵格布局中的子視圖都將依次放入葉子?xùn)鸥竦膮^(qū)域中
@protocol MyGrid <MyGridAction>
//設(shè)置和獲取柵格的尺寸
@property(nonatomic, assign) CGFloat measure;
//得到父柵格。根柵格的父柵格為nil
@property(nonatomic, weak, readonly) id<MyGrid> superGrid;
//得到所有子?xùn)鸥?@property(nonatomic, strong, readonly) NSArray<id<MyGrid>> *subGrids;
//克隆出一個(gè)新柵格以及其下的所有子?xùn)鸥瘛?-(id<MyGrid>)cloneGrid;
/**
柵格內(nèi)子?xùn)鸥裰g的間距余蟹。
*/
@property(nonatomic, assign) CGFloat subviewSpace;
/**
柵格內(nèi)子?xùn)鸥窕蛘呷~子?xùn)鸥駜?nèi)視圖的四周內(nèi)邊距卷胯。
*/
@property(nonatomic, assign) UIEdgeInsets padding;
/**
柵格內(nèi)子?xùn)鸥窕蛘呷~子?xùn)鸥駜?nèi)視圖的對(duì)齊停靠方式.
1.對(duì)于非葉子?xùn)鸥駚?lái)說(shuō)只能設(shè)置一個(gè)方向的屯疲靠窑睁。具體只能設(shè)置左中右或者上中下
2.對(duì)于葉子?xùn)鸥駚?lái)說(shuō),如果設(shè)置了gravity 則填充的子視圖必須要設(shè)置明確的尺寸葵孤。
*/
@property(nonatomic, assign) MyGravity gravity;
/**
占位標(biāo)志卵慰,只用葉子?xùn)鸥瘢?dāng)設(shè)置為YES時(shí)則表示這個(gè)格子只用于占位佛呻,子視圖不能填充到這個(gè)柵格中裳朋。
*/
@property(nonatomic, assign) BOOL placeholder;
/**
錨點(diǎn)標(biāo)志,表示這個(gè)柵格雖然是非葉子?xùn)鸥裣胖部梢杂脕?lái)填充視圖鲤嫡。如果將非葉子?xùn)鸥竦腻^點(diǎn)標(biāo)志設(shè)置為YES,那么這個(gè)柵格也可以用來(lái)填充子視圖绑莺,一般用來(lái)當(dāng)做背景視圖使用暖眼。
*/
@property(nonatomic, assign) BOOL anchor;
/**頂部邊界線*/
@property(nonatomic, strong) MyBorderline *topBorderline;
/**頭部邊界線*/
@property(nonatomic, strong) MyBorderline *leadingBorderline;
/**底部邊界線*/
@property(nonatomic, strong) MyBorderline *bottomBorderline;
/**尾部邊界線*/
@property(nonatomic, strong) MyBorderline *trailingBorderline;
/**如果您不需要考慮國(guó)際化的問(wèn)題則請(qǐng)用這個(gè)屬性設(shè)置左邊邊界線,否則用leadingBorderline*/
@property(nonatomic, strong) MyBorderline *leftBorderline;
/**如果您不需要考慮國(guó)際化的問(wèn)題則請(qǐng)用這個(gè)屬性設(shè)置右邊邊界線纺裁,否則用trailingBorderline*/
@property(nonatomic, strong) MyBorderline *rightBorderline;
/**
添加行柵格诫肠,返回新的柵格。其中的measure可以設(shè)置如下的值:
1.大于等于1的常數(shù)欺缘,表示固定尺寸栋豫。
2.大于0小于1的常數(shù),表示占用整體尺寸的比例
3.小于0大于-1的常數(shù)谚殊,表示占用剩余尺寸的比例
4.MyLayoutSize.wrap 表示尺寸由子?xùn)鸥癜? 5.MyLayoutSize.fill 表示占用柵格剩余的尺寸
*/
-(id<MyGrid>)addRow:(CGFloat)measure;
/**
添加列柵格丧鸯,返回新的柵格。其中的measure可以設(shè)置如下的值:
1.大于等于1的常數(shù)嫩絮,表示固定尺寸丛肢。
2.大于0小于1的常數(shù)围肥,表示占用整體尺寸的比例
3.小于0大于-1的常數(shù),表示占用剩余尺寸的比例
4.MyLayoutSize.wrap 表示尺寸由子?xùn)鸥癜? 5.MyLayoutSize.fill 表示占用柵格剩余的尺寸
*/
-(id<MyGrid>)addCol:(CGFloat)measure;
//添加?xùn)鸥穹湓酰祷乇惶砑拥臇鸥衲驴獭_@個(gè)方法和下面的cloneGrid配合使用可以用來(lái)構(gòu)建那些需要重復(fù)添加?xùn)鸥竦膱?chǎng)景。
-(id<MyGrid>)addRowGrid:(id<MyGrid>)grid;
-(id<MyGrid>)addColGrid:(id<MyGrid>)grid;
-(id<MyGrid>)addRowGrid:(id<MyGrid>)grid measure:(CGFloat)measure;
-(id<MyGrid>)addColGrid:(id<MyGrid>)grid measure:(CGFloat)measure;
//從父柵格中刪除杠步。
-(void)removeFromSuperGrid;
//用字典的方式來(lái)構(gòu)造柵格氢伟。
@property(nonatomic, strong) NSDictionary *gridDictionary;
@end
案例
演示
數(shù)據(jù)
Demo4
{"padding":"{10,0,10,0}","tag":1000,"rows":[{"size":120},{"size":20},
{"size":150,"tag":1,"cols":[{"size":"fill","rows":[{"size":"fill","cols":
[{"size":"20%"},{"size":"20%"},{"size":"20%"},{"size":"20%"},
{"size":"20%"}]},{"size":"fill","cols":[{"size":"20%"},{"size":"20%"},
{"size":"20%"},{"size":"20%"},{"size":"20%"}]}]}]},{"size":5,},
{"size":"fill","cols":[{"size":"50%","padding":"{0,5,0,5}","right-
borderline":{"head":1,"tail":1,"offset":1,"thick":
1,"color":"#EEEEEE"},"bottom-borderline":{"head":1,"tail":1,"offset":
1,"thick":1,"color":"#EEEEEE"},"tag":2,"action":"handleTap:","rows":
[{"size":40,"cols":[{"anchor":true,"size":80,"padding":"{5,5,5,5}","space":
5,"rows":[{"size":"fill"},{"size":"fill"}]},
{"size":"fill","padding":"{5,5,5,5}","space":5,"rows":[{"size":"fill"},
{"size":"fill"}]}]},{"space":5,"size":"fill","cols":[{"padding":"{5, 5, 5,
5}","size":"fill"},{"padding":"{5, 5, 5, 5}","size":"fill"}]},
{"overlap":"bottom|left","padding":"{0,0,5,0}"}]},
{"size":"50%","padding":"{0,5,0,5}","right-borderline":{"head":1,"tail":
1,"offset":1,"thick":1,"color":"#EEEEEE"},"bottom-borderline":{"head":
1,"tail":1,"offset":1,"thick":
1,"color":"#EEEEEE"},"action":"handleTap:","tag":3,"rows":
[{"size":"fill","cols":[{"size":"fill","rows":[{"size":"wrap"},
{"size":"wrap"},{"padding":"{5, 5, 5, 5}","size":"wrap"}]},{"padding":"{5,
5, 5, 5}","size":"fill"}]}]}]},{"size":"fill","cols":
[{"size":"50%","padding":"{0,5,0,5}","right-borderline":{"head":1,"tail":
1,"offset":1,"thick":1,"color":"#EEEEEE"},"bottom-borderline":{"head":
1,"tail":1,"offset":1,"thick":1,"color":"#EEEEEE"},"tag":
3,"action":"handleTap:","rows":[{"size":"fill","cols":
[{"size":"fill","rows":[{"size":"wrap"},{"size":"wrap"},{"padding":"{5, 5, 5, 5}","size":"wrap"}]},{"padding":"{5, 5, 5, 5}","size":"fill"}]}]},
{"size":"50%","padding":"{0,5,0,5}","right-borderline":{"head":1,"tail":
1,"offset":1,"thick":1,"color":"#EEEEEE"},"bottom-borderline":{"head":
1,"tail":1,"offset":1,"thick":1,"color":"#EEEEEE"},"tag":
3,"action":"handleTap:","rows":[{"size":"fill","cols":
[{"size":"fill","rows":[{"size":"wrap"},{"size":"wrap"},{"padding":"{5, 5,
5, 5}","size":"wrap"}]},{"padding":"{5, 5, 5, 5}","size":"fill"}]},
{"overlap":"bottom|left","padding":"{0,0,5,0}"}]}]}]}
Demo5
{"rows":[{"size":240,"padding":"{10,10,5,10}","space":5,"cols":
[{"size":"40%","anchor":true,"tag":222,"padding":"{0,20,0,20}","rows":
[{"size":35,"anchor":"true","rows":[{"size":"fill"}]},{"size":
30,"anchor":"true","rows":[{"size":"fill"}]}]},{"size":"30%","space":
5,"rows":[{"size":"fill","tag":333,"anchor":"true","rows":[{"size":30}]},
{"size":"fill","anchor":"true","tag":333,"rows":[{"size":30}]}]},
{"size":"30%","space":5,"rows":[{"size":"fill","tag":
333,"anchor":"true","rows":[{"size":30}]},
{"size":"fill","anchor":"true","tag":333,"rows":[{"size":30}]}]}]},
{"size":"fill","anchor":true,"tag":111,"top-borderline":{"thick":
10,"offset":5,"color":"#D1D1D1"},"space":
5,"padding":"{10,10,10,10}","rows":[{"size":40,"tag":1},
{"size":"fill","space":10,"cols":[{"size":"fill","anchor":true,"tag":
2,"rows":[{"size":"fill","placeholder":true},{"size":
50,"anchor":true,"cols":[{"placeholder":true,"size":"50%"},
{"size":"50%"}]}]},{"size":"fill","anchor":true,"tag":2,"rows":
[{"size":"fill","placeholder":true},{"size":50,"anchor":true,"cols":
[{"placeholder":true,"size":"50%"},{"size":"50%"}]}]}]},{"size":25,"bottom-
borderline":{"thick":1,"color":"#D1D1D1"}},{"size":
40,"padding":"{10,5,10,5}","cols":[{"size":"fill"},{"size":"wrap"}]}]}]}