UICollectionView - 在其他单元格中重复的子视图实例
Posted
技术标签:
【中文标题】UICollectionView - 在其他单元格中重复的子视图实例【英文标题】:UICollectionView - Instance of subview duplicated in other cells 【发布时间】:2013-08-16 15:25:47 【问题描述】:首先,我的应用程序的粗略描述是一个特定组织的杂志库应用程序。
-
我有一个定制的 UICollectionViewCell 和一个故事板原型。原型中有 3 个视图 - UIImageView、UILabel、UILabel。
另外在collectionView:cellForItemAtIndexPath:
中,我创建了一个
还有一个
UIProgressView 其中tag=indexPath.item
和 hidden=YES
。然后我将 UIProgressView 添加到一个数组 - self.progressViewArray 与单元格的 indexPath.item 位于 same index .
每次点击特定单元格的“下载”按钮并调用 downloadButtonTapped:
时,我都会得到 cell 和 indexPath sender 的 superview 的 superview,即 cell。然后我检查[self.progressViewArray[indexPath.item] tag] == indexPath.item
。如果满足条件,则执行 [self.progressViewArray[indexPath.item] setHidden:NO]
。
我有一个包含 22 个对象的数据源,因此我有 22 个单元格。到目前为止,一切都像我想要的那样工作。即使我将单元格滚动出视图(出队)并返回视图(回收),UIProgressView 仍然存在。
问题:
progressView 也重新出现在其他单元格中!例如。如果我点击单元格 3 的“下载”按钮,UIProgressView 会正确显示在该单元格中但是,单元格 10 和 19 也显示“重复的”UIProgressView。这个问题也适用于其他细胞。例如。当我点击单元格 20 的“下载”时,我向上滚动并看到单元格 12 和 4 具有相同的加载 UIProgressViews,就好像这些杂志也在被下载一样。
之所以提到same是因为我有一个setDownloadProgressBlock
,它会更新 UIProgressViews 的进度以及单元格 3、10 和 19 UIProgressViews 的进度一起进行。
我真的希望我能在这里找到一些帮助,因为我已经为这个问题绞尽脑汁了很多天。
附注编辑调试尝试如下。
以下是涉及的方法:
collectionView:cellForItemAtIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
static NSString *identifier = @"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
// * ========== Configure Cell ========== *
// Initialisation of UIImageViews and UILabels here.
// ...
// CREATION OF CELL'S DOWNLOADBUTTON
UIButton *downloadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[downloadButton addTarget:self action:@selector(downloadButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
[downloadButton setFrame:CGRectMake(178, 197, 140, 44)];
[downloadButton setTitle:[self setDownloadButtonTitleAtIndexPath:indexPath.item] forState:UIControlStateNormal];
[downloadButton setTitle:@"Downloading..." forState:UIControlStateDisabled];
[downloadButton setEnabled:YES];
[downloadButton setUserInteractionEnabled:YES];
[downloadButton setTag:indexPath.item];
[cell.contentView addSubview:downloadButton];
// CREATION OF CELL'S UIPROGRESSVIEW
UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
[progressView setFrame:CGRectMake(20, 248, 150, 9)];
[progressView setHidden:YES];
[progressView setTag:indexPath.item];
[self.progressViewArray addObject:progressView];
// This chunk is to prevent creating new progress views when the cells are being recycled.
if ([self.progressViewArray[indexPath.item] tag] != progressView.tag)
[self.progressViewArray replaceObjectAtIndex:indexPath.item withObject:progressView];
[cell.contentView addSubview:self.progressViewArray[indexPath.item]];
// * ---------- Configure Cell ---------- *
return cell;
downloadButtonTapped:
- (IBAction)downloadButtonTapped:(id)sender
// Get the indexPath of tapped row.
UICollectionViewCell *cell = (UICollectionViewCell *)[[sender superview] superview];
NSIndexPath *indexPath = [self.collectionView indexPathForCell:cell];
// If file does not exist.
if (![[NSFileManager defaultManager] fileExistsAtPath:filePath])
// SHOW THE CELL'S HIDDEN UIPROGRESSVIEW
if ([self.progressViewArray[indexPath.item] tag] == indexPath.item)
[self.progressViewArray[indexPath.item] setHidden:NO];
// AFHTTPRequestionOperation code here...
// Track download progress.
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
for (UIProgressView *progressView in self.progressViewArray)
if (progressView.tag == indexPath.item)
[progressView setProgress:(float) totalBytesRead / totalBytesExpectedToRead];
];
// Post download codes etc ...
[operation start];
感谢您抽出宝贵的时间。我很感激...
编辑:
作为另一次调试尝试,我在return cell;
之前做了一个NSLog(@"%@ at indexPath #%d", self.progressViewArray[indexPath.item], indexPath.item);
,只是为了确认只有被点击的单元格的 UIProgressView 受到影响(setHidden=NO)而且确实如此。 p>
我点击了单元格 3 的下载按钮,滚动到底部并回到 collectionView 的顶部,像往常一样看到好像单元格 10 和 19 的进度视图也处于活动状态,这就是我记录的内容。如您所见,当下载处于活动状态时,日志显示只有单元格 3 的 progressView (tag=3) 为 (setHidden=NO)。单元格 10 和 19 仍然隐藏/不受影响。但我不明白为什么我会在那里看到一个活跃的 progressView。
这是日志:
2013-08-17 10:59:33.179 SFCCA[22885:907] <UIProgressView: 0x1c5bca00; frame = (20 248; 150 9); hidden = YES; opaque = NO; layer = <CALayer: 0x1c5d1000>> at indexPath #0
2013-08-17 10:59:33.187 SFCCA[22885:907] <UIProgressView: 0x1c59c7c0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 1; layer = <CALayer: 0x1c5bb310>> at indexPath #1
2013-08-17 10:59:33.193 SFCCA[22885:907] <UIProgressView: 0x1c5aa1f0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 2; layer = <CALayer: 0x1c5aa270>> at indexPath #2
2013-08-17 10:59:33.201 SFCCA[22885:907] <UIProgressView: 0x1c5b9860; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 3; layer = <CALayer: 0x1c5b9a30>> at indexPath #3
2013-08-17 10:59:33.207 SFCCA[22885:907] <UIProgressView: 0x1c5aa670; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 4; layer = <CALayer: 0x1c5b8d60>> at indexPath #4
2013-08-17 10:59:33.214 SFCCA[22885:907] <UIProgressView: 0x1c5b51d0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 5; layer = <CALayer: 0x1c5b5270>> at indexPath #5
// Here, I have tapped cell 3's "Download" button.
// Notice that at the bottom of the log, when I have scrolled off cell 3 and back, the log shows that the progressView (tag=3) in cell 3 is hidden=NO
2013-08-17 10:59:43.389 SFCCA[22885:907] downloadButtonTapped - File does not exist. Download then read PDF.
2013-08-17 10:59:43.929 SFCCA[22885:907] <UIProgressView: 0x1c5d5a10; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 6; layer = <CALayer: 0x1c5b4420>> at indexPath #6
2013-08-17 10:59:43.938 SFCCA[22885:907] <UIProgressView: 0x1c5cd8e0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 7; layer = <CALayer: 0x1c5b68d0>> at indexPath #7
2013-08-17 10:59:44.216 SFCCA[22885:907] <UIProgressView: 0x1d8c3b90; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 8; layer = <CALayer: 0x1d8c3c30>> at indexPath #8
2013-08-17 10:59:44.223 SFCCA[22885:907] <UIProgressView: 0x1c5e08d0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 9; layer = <CALayer: 0x1c5b9330>> at indexPath #9
2013-08-17 10:59:44.600 SFCCA[22885:907] <UIProgressView: 0x1d8c9aa0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 10; layer = <CALayer: 0x1d8c9480>> at indexPath #10
2013-08-17 10:59:44.607 SFCCA[22885:907] <UIProgressView: 0x1d8cb590; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 11; layer = <CALayer: 0x1d8cb4b0>> at indexPath #11
2013-08-17 10:59:45.160 SFCCA[22885:907] <UIProgressView: 0x1d8b9e20; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 12; layer = <CALayer: 0x1d8a6140>> at indexPath #12
2013-08-17 10:59:45.171 SFCCA[22885:907] <UIProgressView: 0x1d8cc060; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 13; layer = <CALayer: 0x1d8ca870>> at indexPath #13
2013-08-17 10:59:45.813 SFCCA[22885:907] <UIProgressView: 0x1d88dc10; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 14; layer = <CALayer: 0x1d88dc90>> at indexPath #14
2013-08-17 10:59:45.822 SFCCA[22885:907] <UIProgressView: 0x1d8cc9e0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 15; layer = <CALayer: 0x1d872110>> at indexPath #15
2013-08-17 10:59:46.154 SFCCA[22885:907] <UIProgressView: 0x1c5ed300; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 16; layer = <CALayer: 0x1c5ed280>> at indexPath #16
2013-08-17 10:59:46.162 SFCCA[22885:907] <UIProgressView: 0x1c5eeae0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 17; layer = <CALayer: 0x1c5eea00>> at indexPath #17
2013-08-17 10:59:46.652 SFCCA[22885:907] <UIProgressView: 0x1c5ee0f0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 18; layer = <CALayer: 0x1c5e35f0>> at indexPath #18
2013-08-17 10:59:46.660 SFCCA[22885:907] <UIProgressView: 0x1c5efc70; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 19; layer = <CALayer: 0x1c5ee320>> at indexPath #19
2013-08-17 10:59:46.903 SFCCA[22885:907] <UIProgressView: 0x1c5e8b30; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 20; layer = <CALayer: 0x1c5e4aa0>> at indexPath #20
2013-08-17 10:59:46.914 SFCCA[22885:907] <UIProgressView: 0x1c5e8fd0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 21; layer = <CALayer: 0x1c5e7e50>> at indexPath #21
2013-08-17 10:59:48.583 SFCCA[22885:907] <UIProgressView: 0x1d88dc10; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 14; layer = <CALayer: 0x1d88dc90>> at indexPath #14
2013-08-17 10:59:48.590 SFCCA[22885:907] <UIProgressView: 0x1d8cc9e0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 15; layer = <CALayer: 0x1d872110>> at indexPath #15
2013-08-17 10:59:49.118 SFCCA[22885:907] <UIProgressView: 0x1d8b9e20; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 12; layer = <CALayer: 0x1d8a6140>> at indexPath #12
2013-08-17 10:59:49.127 SFCCA[22885:907] <UIProgressView: 0x1d8cc060; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 13; layer = <CALayer: 0x1d8ca870>> at indexPath #13
2013-08-17 10:59:49.730 SFCCA[22885:907] <UIProgressView: 0x1d8c9aa0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 10; layer = <CALayer: 0x1d8c9480>> at indexPath #10
2013-08-17 10:59:49.736 SFCCA[22885:907] <UIProgressView: 0x1d8cb590; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 11; layer = <CALayer: 0x1d8cb4b0>> at indexPath #11
2013-08-17 10:59:50.106 SFCCA[22885:907] <UIProgressView: 0x1d8c3b90; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 8; layer = <CALayer: 0x1d8c3c30>> at indexPath #8
2013-08-17 10:59:50.113 SFCCA[22885:907] <UIProgressView: 0x1c5e08d0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 9; layer = <CALayer: 0x1c5b9330>> at indexPath #9
2013-08-17 10:59:50.643 SFCCA[22885:907] <UIProgressView: 0x1c5d5a10; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 6; layer = <CALayer: 0x1c5b4420>> at indexPath #6
2013-08-17 10:59:50.649 SFCCA[22885:907] <UIProgressView: 0x1c5cd8e0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 7; layer = <CALayer: 0x1c5b68d0>> at indexPath #7
2013-08-17 10:59:50.967 SFCCA[22885:907] <UIProgressView: 0x1c5aa670; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 4; layer = <CALayer: 0x1c5b8d60>> at indexPath #4
2013-08-17 10:59:50.973 SFCCA[22885:907] <UIProgressView: 0x1c5b51d0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 5; layer = <CALayer: 0x1c5b5270>> at indexPath #5
2013-08-17 10:59:51.593 SFCCA[22885:907] <UIProgressView: 0x1c5aa1f0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 2; layer = <CALayer: 0x1c5aa270>> at indexPath #2
2013-08-17 10:59:51.598 SFCCA[22885:907] <UIProgressView: 0x1c5b9860; frame = (20 248; 150 9); opaque = NO; tag = 3; layer = <CALayer: 0x1c5b9a30>> at indexPath #3
2013-08-17 10:59:51.983 SFCCA[22885:907] <UIProgressView: 0x1c5bca00; frame = (20 248; 150 9); hidden = YES; opaque = NO; layer = <CALayer: 0x1c5d1000>> at indexPath #0
2013-08-17 10:59:51.995 SFCCA[22885:907] <UIProgressView: 0x1c59c7c0; frame = (20 248; 150 9); hidden = YES; opaque = NO; tag = 1; layer = <CALayer: 0x1c5bb310>> at indexPath #1
【问题讨论】:
【参考方案1】:经过 2 周的努力,终于解决了这个问题。简单的解决方案,但我之前没有想到。
我有一个属性如下@property (strong, nonatomic) NSMutableArray *progressViewsArray;
。不要忘记分配并初始化它。我是在viewDidLoad
做的。
在collectionView:cellForItemAtIndexPath:
中,我在返回单元格之前使用了以下逻辑。
for (UIProgressView *progressView in cell.contentView.subviews)
if ([progressView isKindOfClass:[UIProgressView class]])
[progressView removeFromSuperview];
for (UIProgressView *progressView in self.progressViewsArray)
if (progressView.tag == indexPath.item)
[cell.contentView addSubview:progressView];
在downloadButtonTapped:
中,这就是我创建 UIProgressView 实例的方式:
UIProgressView *progressView = [[UIProgressView alloc] initWithProgressViewStyle:UIProgressViewStyleDefault];
progressView.frame = CGRectMake(178, 180, 170, 9);
[progressView setTag:indexPath.item];
[cell.contentView addSubview:progressView];
[self.progressViewsArray addObject:progressView];
在 AFNetworking 的 setDownloadProgressBlock (downloadButtonTapped:
) 中:
float progress = (float) totalBytesRead / totalBytesExpectedToRead;
[progressView setProgress:progress];
最后在 AFNetworking 的 setCompletionBlock (downloadButtonTapped:
) 中:
NSMutableArray *progressViewsToDelete = [[NSMutableArray alloc] init];
for (UIProgressView *pv in self.progressViewsArray)
if (pv.tag == indexPath.item)
[progressViewsToDelete addObject:pv];
if (progressViewsToDelete.count > 0)
[self.progressViewsArray removeObjectsInArray:progressViewsToDelete];
[self.collectionView reloadItemsAtIndexPaths:@[indexPath]]; // To reflect changes.
希望这对未来的人有所帮助,干杯!
【讨论】:
你真的应该在你的细胞子类的 prepareForReuse 中这样做。【参考方案2】:您应该将所有视图添加到原型单元格中,并将其中一些设置为隐藏。具体来说,在collectionView:cellForItemAtIndexPath:
中,您应该设置您配置的所有视图的hidden
属性,以便在需要时使其可见并在不需要时隐藏它们。那么不管单元格是新的还是重复使用的,您始终保证正确的视图是可见的。
在您当前的解决方案中,您有一些逻辑可以防止创建新的进度视图(如果您已经有一个)。但是,您永远不会真正从单元格中删除任何进度视图。因此,当您重用单元格时,它可能仍然具有作为子视图的进度视图。使用隐藏或显示视图(并设置进度值)的方法可以避免这种情况。
【讨论】:
嗨@Wain 感谢您的回复。我没有在原型单元格中包含 UIProgressView 是因为我意识到我需要将每个 UIProgressView 的标记分配给 indexPath.item 以便我可以识别要 unhide 的 UIProgressView。在防止创建新 UIProgressViews 的逻辑中,它做了我想要的 - 当我点击的单元格滚动关闭视图并重新打开时,相同的 UIProgressView 仍然存在并正在加载。问题是当我什至没有说明这些单元格的 indexPath 时,相同的 UIProgressView 也出现在其他单元格上。我在这里做错了什么?谢谢。【参考方案3】:我也有类似的问题。我解决了它。你已经在这个方法中更改了单元格的子视图:- (IBAction)downloadButtonTapped:(id)sender
,而你没有将这个子视图更新为方法:collectionView:cellForItemAtIndexPath:
。当重用单元工作时,它只是从这个方法中获取视图:collectionView:cellForItemAtIndexPath:
,并且不包括在这个方法之外更改的子视图,所以你应该在方法collectionView:cellForItemAtIndexPath:
中做一些事情来更新你对子视图的更改细胞。无论如何,我希望这可以帮助你。
【讨论】:
抱歉,我没有更新collectionView:cellForItemAtIndexPath:
中单元格的子视图,我不明白您的意思。 [cell.contentView addSubview:self.progressViewArray[indexPath.item]];
? 我以为我已经做到了以上是关于UICollectionView - 在其他单元格中重复的子视图实例的主要内容,如果未能解决你的问题,请参考以下文章
如果从 UICollectionView 的其他部分中选择了一个单元格,则取消选择所有其他选择
UICollectionView,单元格选择不起作用,单元格滚动正常