IOS15瀑布流布局
2021-11-28 本文已影响0人
Johnson_9d92
IOS15瀑布流布局
环境
ios 15
xcode 13.0
效果图
瀑布流效果图
核心源码:
我这里使用的nib,storyBoard加载的。
//
// LJWaterflowLayout.m
// WaterFlowDemo
//
// Created by lujun on 2021/11/28.
//
#import "LJWaterflowLayout.h"
static const CGFloat LJDefaultColumnCount = 3;
static const CGFloat LJDefaultColumnMargin = 10;
static const CGFloat LJDefaultRowMargin = 10;
static const UIEdgeInsets LJDefaultEdgeInsets = {10,10,10,10};
@interface LJWaterflowLayout()
@property(nonatomic,strong)NSMutableArray *attrsArr;
@property (nonatomic, assign) CGFloat contentHeight;
@property(nonatomic,strong)NSMutableArray *columnHeights;
- (CGFloat)rowMargin;
- (CGFloat)columnMargin;
- (NSInteger)columnCount;
- (UIEdgeInsets)edgeInsets;
@end
@implementation LJWaterflowLayout
- (CGFloat)rowMargin
{
if ([self.delegate respondsToSelector:@selector(rowMarginInWaterflowLayout:)]) {
return [self.delegate rowMarginInWaterflowLayout:self];
} else {
return LJDefaultRowMargin;
}
}
- (CGFloat)columnMargin
{
if ([self.delegate respondsToSelector:@selector(columnMarginInWaterflowLayout:)]) {
return [self.delegate columnMarginInWaterflowLayout:self];
} else {
return LJDefaultColumnMargin;
}
}
- (NSInteger)columnCount
{
if ([self.delegate respondsToSelector:@selector(columnCountInWaterflowLayout:)]) {
return [self.delegate columnCountInWaterflowLayout:self];
} else {
return LJDefaultColumnCount;
}
}
- (UIEdgeInsets)edgeInsets
{
if ([self.delegate respondsToSelector:@selector(edgeInsetsInWaterflowLayout:)]) {
return [self.delegate edgeInsetsInWaterflowLayout:self];
} else {
return LJDefaultEdgeInsets;
}
}
- (void)prepareLayout{
[super prepareLayout];
self.contentHeight = 0;
//[self.collectionView setShowsVerticalScrollIndicator:NO];
[self.columnHeights removeAllObjects];
for(NSInteger i=0;i<LJDefaultColumnCount;i++){
[self.columnHeights addObject:@(LJDefaultEdgeInsets.top)];
}
[self.attrsArr removeAllObjects];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for(NSInteger i = 0;i < count; i++){
NSIndexPath *indexPath = [NSIndexPath indexPathForItem:i inSection:0];
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:indexPath];
[self.attrsArr addObject:attrs];
}
}
- (NSArray<__kindof UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect{
return self.attrsArr;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath{
// 创建布局属性
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
// collectionView的宽度
// CGFloat collectionViewW = [UIScreen mainScreen].bounds.size.width;
CGFloat collectionViewW = self.collectionView.frame.size.width;
// 设置布局属性的frame
CGFloat w = (collectionViewW - self.edgeInsets.left - self.edgeInsets.right - (self.columnCount - 1) * self.columnMargin) / self.columnCount;
CGFloat h = [self.delegate waterflowLayout:self heightForItemAtIndex:indexPath.item itemWidth:w];
// 找出高度最短的那一列
NSInteger destColumn = 0;
CGFloat minColumnHeight = [self.columnHeights[0] doubleValue];
for (NSInteger i = 1; i < self.columnCount; i++) {
// 取得第i列的高度
CGFloat columnHeight = [self.columnHeights[i] doubleValue];
if (minColumnHeight > columnHeight) {
minColumnHeight = columnHeight;
destColumn = i;
}
}
CGFloat x = self.edgeInsets.left + destColumn * (w + self.columnMargin);
CGFloat y = minColumnHeight;
if (y != self.edgeInsets.top) {
y += self.rowMargin;
}
attrs.frame = CGRectMake(x, y, w, h);
// 更新最短那列的高度
self.columnHeights[destColumn] = @(CGRectGetMaxY(attrs.frame));
// 记录内容的高度
CGFloat columnHeight = [self.columnHeights[destColumn] doubleValue];
if (self.contentHeight < columnHeight) {
self.contentHeight = columnHeight;
}
return attrs;
}
- (CGSize)collectionViewContentSize{
return CGSizeMake(0, self.contentHeight + self.edgeInsets.bottom);
}
- (NSMutableArray *)columnHeights{
if(!_columnHeights){
_columnHeights = [NSMutableArray array];
}
return _columnHeights;
}
- (NSMutableArray *)attrsArr{
if(!_attrsArr){
_attrsArr = [NSMutableArray array];
}
return _attrsArr;
}
@end
第二段
#import "MJExtension.h"
#import "LJShop.h"
//
// ViewController.m
// WaterFlowDemo
//
// Created by lujun on 2021/11/28.
//
#import "ViewController.h"
#import "MJRefresh.h"
#import "LJShopCell.h"
#import "LJWaterflowLayout.h"
//#import "UIImageView+WebCache.h"
#define k_title_color [UIColor whiteColor]
#define k_main_tab_bar_color [UIColor redColor]
#define TEXT_BIG_S_FONT18 [UIFont systemFontOfSize:24]
@interface ViewController () <LJWaterflowLayoutDelegate>
@property(nonatomic,strong)NSMutableArray *shops;
@end
@implementation ViewController
- (NSMutableArray *)shops{
if(!_shops){
_shops = [NSMutableArray array];
}
return _shops;
}
static NSString * const reuseIdentifier = @"shop";
- (void)viewDidLoad {
[super viewDidLoad];
[self setupLayout];
[self setupRefresh];
if (@available(iOS 15.0, *)) {
UINavigationBarAppearance *appperance = [[UINavigationBarAppearance alloc] init];
//添加背景色
appperance.backgroundColor = k_main_tab_bar_color;
appperance.shadowImage = [[UIImage alloc]init];
appperance.shadowColor = nil;
//设置字体颜色大小
[appperance setTitleTextAttributes:@{NSForegroundColorAttributeName:k_title_color,NSFontAttributeName:TEXT_BIG_S_FONT18}];
self.navigationController.navigationBar.standardAppearance = appperance;
self.navigationController.navigationBar.scrollEdgeAppearance = appperance;
self.navigationController.navigationBar.compactAppearance = appperance;
self.navigationController.navigationBar.compactScrollEdgeAppearance = appperance;
}
self.navigationItem.title = @"瀑布流布局";
// [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier];
[self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([LJShopCell class]) bundle:nil] forCellWithReuseIdentifier:reuseIdentifier];
LJWaterflowLayout * watet = (LJWaterflowLayout *) [self.collectionView collectionViewLayout];
watet.delegate = self;
}
- (CGFloat)waterflowLayout:(LJWaterflowLayout *)waterflowLayout heightForItemAtIndex:(NSUInteger)index itemWidth:(CGFloat)itemWidth{
// NSLog(@"%s",__func__);
// NSLog(@"大军");
LJShop *shop = self.shops[index];
return itemWidth * shop.h / shop.w;
}
-(void)setupLayout{
}
-(void)setupRefresh{
self.collectionView.header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewShops)];
[self.collectionView.header beginRefreshing];
self.collectionView.footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreShops)];
self.collectionView.footer.hidden = NO;
}
-(void)loadMoreShops{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSArray *shops = [LJShop objectArrayWithFilename:@"mogujie.plist"];
// [self.shops removeAllObjects];
[self.shops addObjectsFromArray:shops];
[self.collectionView reloadData];
[self.collectionView.footer endRefreshing];
});
}
-(void)loadNewShops{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSArray *shops = [LJShop objectArrayWithFilename:@"mogujie.plist"];
[self.shops removeAllObjects];
[self.shops addObjectsFromArray:shops];
[self.collectionView reloadData];
[self.collectionView.header endRefreshing];
});
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
self.collectionView.footer.hidden = self.shops.count == 0;
return self.shops.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
LJShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
cell.shop = self.shops[indexPath.item];
return cell;
}
#pragma mark - WaterFlowLayout的代理方法,总共4个
- (CGFloat)rowMarginInWaterflowLayout:(LJWaterflowLayout *)waterflowLayout{
return 10;
}
- (CGFloat)columnCountInWaterflowLayout:(LJWaterflowLayout *)waterflowLayout{
return 3;
}
@end