Skip to content
This repository was archived by the owner on Oct 19, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Tangram/Core/TangramView.m
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,8 @@ - (void)resetLayoutEnterTimes

- (void)setContentOffset:(CGPoint)contentOffset
{
[super setContentOffset:contentOffset];

NSUInteger min = [self layoutIndexByHeight:self.contentOffset.y];
NSUInteger max = [self layoutIndexByHeight:self.contentOffset.y + self.vv_height];
[self.visibleLayoutIdentifierSet removeAllObjects];
Expand Down
117 changes: 42 additions & 75 deletions Tangram/Layouts/TangramWaterFlowLayout.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@
#import <VirtualView/UIView+VirtualView.h>

@interface TangramWaterFlowLayout()
@property (nonatomic, assign) CGRect minRect;
@property (nonatomic, assign) CGRect maxRect;
@property (nonatomic, strong) NSMutableDictionary *bottomRects;

@property (nonatomic, strong) NSString *layoutIdentifier;
// 收到reload请求的次数
@property (atomic, assign ) int numberOfReloadRequests;
Expand All @@ -24,7 +22,8 @@ @interface TangramWaterFlowLayout()
@property (nonatomic, strong) NSString *bgImgURL;
@property (nonatomic, strong) UIImageView *bgImageView;


// 每列对应的最底部的rectModel
@property (nonatomic, strong) NSMutableArray *columnsRectModels;


@end
Expand Down Expand Up @@ -104,14 +103,6 @@ - (CGFloat)marginLeft
return [[self.margin tm_safeObjectAtIndex:3] floatValue];
}

- (NSMutableDictionary *)bottomRects
{
if (nil == _bottomRects) {
_bottomRects = [[NSMutableDictionary alloc] init];
}
return _bottomRects;
}

- (CGFloat)cellWidth
{
if (0 == _cellWidth) {
Expand All @@ -136,78 +127,54 @@ -(UIImageView *)bgImageView
//核心·CalculateLayout
-(void)calculateLayout
{
self.minRect = CGRectZero;
self.maxRect = CGRectZero;
[self.bottomRects removeAllObjects];
CGFloat cellX = 0.f;
CGFloat cellY = 0.f;
for (NSUInteger i = 0; i < self.itemModels.count; i++) {
NSObject<TangramItemModelProtocol> *itemModel = [self.itemModels tm_safeObjectAtIndex:i];
cellX = CGRectGetMinX(self.minRect);
//第一行不会受vGap的影响
if (i / self.numberOfColumns == 0) {
cellY = CGRectGetMaxY(self.minRect) + [itemModel marginTop] + [self.padding tm_floatAtIndex:0];
}
else{
cellY = CGRectGetMaxY(self.minRect) + [itemModel marginTop] + self.vGap ;
}
//第一个组件给一个padding 的影响
if (i == 0) {
cellX += [self.padding tm_floatAtIndex:3];
if ([itemModel.display isEqualToString:@"block"]) {
[itemModel setItemFrame:CGRectMake(cellX + [itemModel marginLeft] , cellY, self.vv_width - [itemModel marginRight] - [itemModel marginLeft] - [self.padding tm_floatAtIndex:3] - [self.padding tm_floatAtIndex:1] , itemModel.itemFrame.size.height)];
}
else{
[itemModel setItemFrame:CGRectMake(cellX + [itemModel marginLeft] , cellY, self.cellWidth, itemModel.itemFrame.size.height)];
}
}
else{
[itemModel setItemFrame:CGRectMake(cellX + [itemModel marginLeft] , cellY, self.cellWidth, itemModel.itemFrame.size.height)];
}
CGRect cellFrame = CGRectMake(itemModel.itemFrame.origin.x, itemModel.itemFrame.origin.y, itemModel.itemFrame.size.width, itemModel.itemFrame.size.height + [itemModel marginBottom]);
// 看看是不是变成最大的了
if (CGRectGetMaxY(self.maxRect) < CGRectGetMaxY(cellFrame) + [itemModel marginBottom]) {
self.maxRect = cellFrame;
}
// 更新最下边一行的记录字典,用rect.x做key,保证不重复
[self.bottomRects tm_safeSetObject:[NSValue valueWithCGRect:cellFrame] forKey:[NSString stringWithFormat:@"%f", CGRectGetMinX(cellFrame)]];
// 先随便给一个值,然后去最后一行找
self.minRect = cellFrame;
// 还没排满的时候
if (self.numberOfColumns > self.bottomRects.count) {
self.minRect = CGRectMake(CGRectGetMaxX(self.minRect) + self.hGap , 0.f, 0.f, 0.f);
}
//获取一个对象
NSValue *value = [self.bottomRects.allValues firstObject];
//获取到它的值
CGFloat anyY = CGRectGetMaxY([value CGRectValue]);
BOOL allSameY = YES;
for (NSValue *value in self.bottomRects.allValues) {
CGRect rect = [value CGRectValue];
if (CGRectGetMaxY([value CGRectValue]) != anyY) {
allSameY = NO;
}
if (CGRectGetMaxY(rect) < CGRectGetMaxY(self.minRect)) {
self.minRect = rect;
NSUInteger numberOfColumns = self.numberOfColumns;
CGFloat itemWidth = self.cellWidth;
NSUInteger numberOfLine = (NSUInteger)ceil(self.itemModels.count / (numberOfColumns * 1.0));

_columnsRectModels = [NSMutableArray arrayWithCapacity:numberOfColumns];

CGFloat contentY = [self.padding tm_floatAtIndex:0];
for (NSUInteger line = 0; line < numberOfLine; line++) {
for (NSUInteger j = 0; j < numberOfColumns; j++) {
NSUInteger index = line * numberOfColumns + j;
if (index >= self.itemModels.count) {
break;
}
}
if (allSameY && self.bottomRects.allValues.count >= 2) {
for (NSValue *value in self.bottomRects.allValues) {
CGRect rect = [value CGRectValue];
if (CGRectGetMinX(rect) < CGRectGetMinX(self.minRect)) {
self.minRect = rect;
}
NSObject<TangramItemModelProtocol> *itemModel = [self.itemModels tm_safeObjectAtIndex:index];
CGFloat x = 0;
CGFloat paddingTop = [self.padding tm_floatAtIndex: 0];
CGFloat paddingLeft = [self.padding tm_floatAtIndex: 3];

if (line == 0) {
x = paddingLeft + (itemWidth + _hGap) * j;
[itemModel setItemFrame:CGRectMake(x, paddingTop, itemWidth, itemModel.itemFrame.size.height)];
_columnsRectModels[j] = itemModel;
} else {
NSMutableArray *sortArray = [_columnsRectModels mutableCopy];
[sortArray sortUsingComparator:^NSComparisonResult(NSObject<TangramItemModelProtocol> *obj1, NSObject<TangramItemModelProtocol> *obj2) {
return CGRectGetMaxY(obj1.itemFrame) > CGRectGetMaxY(obj2.itemFrame);
}];
// 排序找到找到高度最小的一个
// 接着最小的一个往下排
NSObject<TangramItemModelProtocol> *minYModel = sortArray.firstObject;
NSUInteger minYColumns = [_columnsRectModels indexOfObject:minYModel];
x = paddingLeft + (itemWidth + _hGap) * minYColumns;
CGFloat y = CGRectGetMaxY(minYModel.itemFrame) + _vGap;
itemModel.itemFrame = CGRectMake(x, y, itemWidth, itemModel.itemFrame.size.height);
_columnsRectModels[minYColumns] = itemModel;
}
CGFloat itemY = CGRectGetMaxY(itemModel.itemFrame);
contentY = MAX(contentY, itemY);
}

}
self.vv_height = MAX(CGRectGetMaxY(self.maxRect), CGRectGetMaxY(self.minRect)) + [self.padding tm_floatAtIndex:2];
contentY += [self.padding tm_floatAtIndex: 2];

self.vv_height = contentY;
if (self.bgImgURL && self.bgImgURL.length > 0) {
self.bgImageView.frame = CGRectMake(0, 0, self.vv_width, self.vv_height);
[self.bgImageView sd_setImageWithURL:[NSURL URLWithString:self.bgImgURL]];
}


}
- (void)heightChangedWithElement:(UIView *)element model:(NSObject<TangramItemModelProtocol> *)model
{
Expand Down
4 changes: 4 additions & 0 deletions TangramDemo/TangramDemo/ViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ - (UIView *)itemInTangramView:(TangramView *)view withModel:(NSObject<TangramIte
}
if (index == 6){
TangramWaterFlowLayout *waterFlowLayout = [[TangramWaterFlowLayout alloc]init];
waterFlowLayout.hGap = 5;
waterFlowLayout.vGap = 5;
waterFlowLayout.padding = @[@5, @5, @5, @5];
waterFlowLayout.margin = @[@10, @10, @10, @10];
return waterFlowLayout;
}
//普通流式布局
Expand Down