ios开发——用UITableView展示多行多列图片

来源:互联网 发布:获取端口号 编辑:程序博客网 时间:2024/05/16 01:55

有时我们可能需要用UITableView通过自定义Cell的方法来展示多行多列的图片,实现类似与UICollectionView的效果。例如电子书等应用。这里我们来实现这个功能。


首先可以自定义一个UIView来代表Cell内的每一个Item,然后以每行三列为例,将其布局到每个cell上。


对这个自定义cell,暴露出一个NSArray属性groupedItem(已分好组的Item)表示有三个Item的数组,这样在TableView中只要cell.groupedItem = ……,在cell中将这三个Item拿出来,分别为View提供数据,让View展示数据即可。

因此关键就是将数据模型(Model)分成2维数组,每个子数组有三个元素。

当从网络上或本地获取所有数据保存到字典中后,可以对这个数组每三个元素加入到一个新数组,然后新数组加入到最终的二维数组。即

[objc] view plaincopyprint?
  1. <span style="font-size:14px;">NSMutableArray *tempArray = nil;  
  2. for (int i = 0; i < self.allBooks.count; i++) {  
  3.     if (i % 3 == 0) {  
  4.         tempArray = [NSMutableArray arrayWithCapacity:3];  
  5.         [self.bookGroup addObject:tempArray];  
  6.     }  
  7.       
  8.     [tempArray addObject:[self.allBooks objectAtIndex:i]];  
  9. }</span>  

allBooks代表保存所有数据的数组,bookGroup表示最终的二维数组。


分好组以后就可以在tableview数据源协议方法中为cell提供数据

[objc] view plaincopyprint?
  1. <span style="font-size:14px;">- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath  
  2. {  
  3.     NSString *cellId = @"CYZBookShelfViewCell";  
  4.     CYZBookCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];  
  5.       
  6.     if (cell == nil) {  
  7.         cell = [[CYZBookCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];  
  8.     }  
  9.       
  10.     cell.booksGroup = [self.bookGroup2D objectAtIndex:indexPath.row];  
  11.       
  12.     return cell;  
  13. }</span>  



在Cell中定义一个数组来接收该行显示的三个Model

[objc] view plaincopyprint?
  1. <span style="font-size:14px;">@interface CYZBookCell : UITableViewCell  
  2.   
  3. /**本cell要展示的三本书*/  
  4. @property (strongnonatomicNSArray *booksGroup;  
  5.   
  6. @end</span>  

然后再initView时建立三个子视图并加入到cell.contentView中,分别为这三个view赋tag值以便在layoutSubview中取得。接着在layoutSubview中设置这三个view的位置、数据等信息。


[objc] view plaincopyprint?
  1. <span style="font-size:14px;"for (int i = 0; i < self.booksGroup.count; i++) {  
  2.      CYZBookItemView *item = (CYZBookItemView *)[self.contentView viewWithTag:100 + i];  
  3.      item.frame = CGRectMake(kHorizontalEdge + (kHorizontalEdge + 80) * i, kVerticalEdge, 80150);  
  4.      item.hidden = NO;       //有数据的item不隐藏  
  5.      item.bookModel = [self.booksGroup objectAtIndex:i];  
  6.      [self addSubview:item];  
  7.        
  8.      //如果不添加以下方法,那么在cell复用时将不会调用子视图的layoutSubview方法,这样数据就无法更新了。  
  9.      [item setNeedsLayout];  
  10.      [item layoutIfNeeded];  
  11.  }</span>  


为什么要再layoutSubview中调用item的setNeedsLayout方法呢?这是因为Cell的复用问题,当cell复用时并不会调用item的layoutSubview方法,因此上拉tableview时展示出来的数据全是与之前重复的。所以我们需要手动让item重新布置子视图。

另一个由cell复用机制引发的问题:依旧是数据重复

我们的数据一般是从网上来的,故数据的数量并不确定,很有可能不是恰好为3的倍数。例如有40个,这是你会发现,本来最后一样应该只有一个数据,却出现了三个,并且后两个是重复的。这就是cell复用引发的另一个问题,为了解决这一问题,我们应该让无数据的item隐藏。怎么判断item有没有数据呢?在上述for循环中,self.booksGroup中保存了有数据的item,因此能进入for循环的即为有数据的。在这里让item显示。

因此,我们可以复写booksGroup的setter,让所有的数据默认隐藏。

[objc] view plaincopyprint?
  1. <span style="font-size:14px;">- (void)setBooksGroup:(NSArray *)booksGroup  
  2. {  
  3.     _booksGroup = booksGroup;  
  4.       
  5.     for (int i = 0; i < booksGroup.count; i++) {  
  6.         CYZBookItemView *item = (CYZBookItemView *)[self.contentView viewWithTag:100 + i];  
  7.         //由于cell的复用问题,当数据并不为3的整数倍时第三个item会填充之前的数据,造成数据重复  
  8.         //为了修正这个问题,没有数据的item应该隐藏,故这里将所有的item隐藏,在layoutSubview方法中有数据的item不隐藏  
  9.         item.hidden = YES;  
  10.     }  
  11. }</span>  


总结一下:

1、我们需要一个自定义视图Item表示在每行cell中的每一列,item可以包含图片、lable……自定义视图,主要功能为展示数据,只要将model对象给他,他就能展示model中的数据。

2、同时还需要一个自定义cell来盛下item,每个cell可以容纳多列,只要传给他一组数组,里面包含这一行的每一列的model对象即可,然后cell将每一个model分别给每一个item。

3、在tableView或其他控制器中将所有数据分组,分成二维数组,每一维都是每一行cell中的所有model,然后在tableview数据源协议中将二维数组的每一个元素(一维数组)分别给每一行让其显示该行的数据。

4、注意在这一过程中由于cell复用引发的一系列数据重复的问题,解决方法:1)手动调用item的setNeedsLayout方法让item刷新。2)让没数据的item隐藏,有数据的item显示。

0 0