实现效果
设计思路
使用MJRefresh框架实现上拉和下拉刷新
使用SDWebImage框架加载图片
商品模型需要包含以下属性
/**商品控件宽度*/ @property (nonatomic, assign) CGFloat w; /**商品控件高度*/ @property (nonatomic, assign) CGFloat h; /**商品图片*/ @property (nonatomic, copy) NSString *img; /**商品价格*/ @property (nonatomic, copy) NSString *price;
通过xib来实现自定义cell(继承自UICollectionViewCell),xib的结构如图
视图的代码实现
包含商品模型属性
/**商品模型*/ @property (nonatomic, strong) LYPShop *shop;
引用xib中的控件
//展示商品图片 @property (weak, nonatomic) IBOutlet UIImageView *imageView; //显示商品价格 @property (weak, nonatomic) IBOutlet UILabel *priceLabel;
重写商品模型的setter,使xib中的控件显示乡音的内容
- (void)setShop:(LYPShop *)shop { _shop = shop; //使用SDWebImage设置商品图片 [self.imageView sd_setImageWithURL:[NSURL URLWithString:shop.img] placeholderImage:[UIImage imageNamed:@"loading"]]; //设置商品价格 self.priceLabel.text = shop.price; }
创建展示商品的容器,即UICollectionView对象,并初始化
- (void)setupCollectionView { //通过封装的自定义布局,创建布局 LYPWaterFlowLayout *layout = [[LYPWaterFlowLayout alloc] init]; //设置layout的代理 layout.delegate = self; //创建collectionView UICollectionView *collectionView = [[UICollectionView alloc] initWithFrame:self.view.bounds collectionViewLayout:layout]; self.collectionView = collectionView; //设置数据源 collectionView.dataSource = self; //将collectionView添加到控制器的view中 [self.view addSubview:collectionView]; }
注册通过xib自定义的cell
/**设置cell的重用标示*/ static NSString *const LYPShopID = @"shop"; - (void)registerCell { //注册cell [self.collectionView registerNib:[UINib nibWithNibName:NSStringFromClass([LYPShopCell class]) bundle:nil] forCellWithReuseIdentifier:LYPShopID]; }
设置商品模型数组
添加成员属性
/**所有的商品模型数组*/ @property (nonatomic, strong) NSMutableArray *shops;
通过懒加载的方式,初始化模型数组
- (NSMutableArray *)shops { if (_shops == nil) { _shops = [NSMutableArray array]; } return _shops; }
实现刷新功能
刷新的业务逻辑,如图
设置上拉刷新和下拉刷新控件
- (void)setupRefresh { //下拉刷新控件 self.collectionView.header = [MJRefreshNormalHeader headerWithRefreshingTarget:self refreshingAction:@selector(loadNewShops)]; //view加载完毕,开始下拉刷新 [self.collectionView.header beginRefreshing]; //上拉刷新控件 self.collectionView.footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreShops)]; //一开始隐藏footer self.collectionView.footer.hidden = YES; }
实现加载数据功能
/**下拉刷新*/ - (void)loadNewShops { //通过该函数模拟网络延迟 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //将字典转成模型 NSArray *shops = [LYPShop objectArrayWithFilename:@"1.plist"]; //清空之前所有的商品模型信息 [self.shops removeAllObjects]; //将最新的商品模型信息添加到模型数组中 [self.shops addObjectsFromArray:shops]; //刷新数据 [self.collectionView reloadData]; //结束刷新 [self.collectionView.header endRefreshing]; }); } /**上拉刷新*/ - (void)loadMoreShops { //通过该函数模拟网络延迟 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ //通过该函数模拟网络延迟 NSArray *shops = [LYPShop objectArrayWithFilename:@"1.plist"]; //将新加载的商品模型信息添加到模型数组中 [self.shops addObjectsFromArray:shops]; //刷新数据 [self.collectionView reloadData]; //结束刷新 [self.collectionView.footer endRefreshing]; }); }
设置collectionView的数据源
设置cell的个数
- (NSInteger)collectionView:(nonnull UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { //设置上拉刷新控件的状态,无商品时不显示 self.collectionView.footer.hidden = self.shops.count == 0; //返回cell的个数 return self.shops.count; }
创建indexPath位置的cell
- (UICollectionViewCell *)collectionView:(nonnull UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath { //通过重用标示从缓存池中取,若取不到,则自动创建 LYPShopCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:LYPShopID forIndexPath:indexPath]; //给视图cell的模型赋值,使其设置cell中控件的显示内容 cell.shop = self.shops[indexPath.item]; return cell; }
实现layout的代理方法,定制布局
设置每个cell的高度
- (CGFloat)waterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout heightForItemAtIndex:(NSInteger)index itemWith:(CGFloat)itemWith { LYPShop *shop = self.shops[index]; //通过比例计算cell的高度 return itemWith * shop.h / shop.w; }
设置列数
- (NSInteger)columnCountInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout { return 2; }
设置行间距
- (CGFloat)rowMarginInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout { return 20; }
设置列间距
- (CGFloat)columnMarginInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout { return 40; }
设置内边距
- (UIEdgeInsets)edgeInsetsInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout { return UIEdgeInsetsMake(20, 10, 10, 30); }
可以简单地通过改变返回列数的代理方法,来改变布局
- (NSInteger)columnCountInWaterFlowLayout:(LYPWaterFlowLayout *)waterFlowLayout { //返回3列 return 3; }
效果如图