【问题标题】:UICollectionViewCell label is reused and placed wronglyUICollectionViewCell 标签被重用和错误放置
【发布时间】:2013-02-19 22:11:07
【问题描述】:

我有一个带有原型单元的 UICollectionView。单元格加载和图像并显示标签。由于单元格的大小不同,它们通过 CollectionViewFlowLayout 进行更改。这很好用。

当我在模拟器中滚动视图时,标签似乎被重复使用并错误地添加到图像上。如何确保不会发生这种情况并且图像在 collectionview 上只有一个标签?

UICollectionView

#pragma mark - Collection view 
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
    self.Data = [NSArray arrayWithObjects:@1, @2, @3, @4, @5, @6, @7, @8, @9, @10, @11, @12, @13, @14, @15, @16, nil];
    return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return self.magazineLayout.count;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    int item = [indexPath row];

    mCell.backgroundColor = [UIColor lightGrayColor];

    // Set Image
    UIImage *image;
    image = [UIImage imageNamed:@"testimage.png"];
    mCell.imageView.image = image; 


    // Set Label
    NSString *title = [[NSString alloc] initWithFormat:@"Image %@", self.Data[item]];
    [mCell addSubview:[self cellTitle:title indexPath:indexPath]];

    return mCell; 
}

// Title will be reused and placed wrongly on pictures !
-(UILabel *)cellTitle:(NSString *)name indexPath:(NSIndexPath *)indexPath {

    CGSize itemSize = [self collectionView:self.collectionView layout:self.collectionView.collectionViewLayout sizeForItemAtIndexPath:indexPath];
    int top = itemSize.height - 40;
    int width = itemSize.width;

    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, top, width, 40)];
    title.textColor = [UIColor blackColor];
    title.text = name;
    title.backgroundColor = [UIColor whiteColor];
    title.alpha = 0.5f;

    return title; 
}

编辑:解决方法

viewWithTag 工作正常,但我无法重新定位标签。可悲的是,我认为这将是最好的方法。这是我没有viewWithTag的解决方法:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    mCell.backgroundColor = [UIColor lightGrayColor];

    // Set Image
    UIImage *image;
    image = [UIImage imageNamed:@"testimage.png"];
    mCell.imageView.image = image; 

    [self cellTitleAndBackground:mCell indexPath:indexPath];

    return mCell; 
}


-(void)cellTitleAndBackground:(MagazineCell *)mCell indexPath:(NSIndexPath *)indexPath {

    // Get title
    NSString *name = [[NSString alloc] initWithFormat:@"Image %@", self.Data[indexPath.row]];

    // Get current cell size
    CGSize itemSize = [self collectionView:self.collectionView layout:self.collectionView.collectionViewLayout sizeForItemAtIndexPath:indexPath];
    int top = itemSize.height - 40;
    int width = itemSize.width;

    // Create title background
    UILabel *titleBackground = [[UILabel alloc] initWithFrame:CGRectMake(0, top, width, 40)];
    titleBackground.backgroundColor = [UIColor blackColor];
    titleBackground.alpha = 0.2f;
    titleBackground.tag = 70;
    [self removeReusedLabel:mCell tag:70]; 
    [mCell addSubview:titleBackground];

    // Create titleLabel
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, top-8, width, 40)];
    titleLabel.textColor = [UIColor whiteColor];
    titleLabel.font = [UIFont boldSystemFontOfSize:14];
    titleLabel.text = name;
    titleLabel.backgroundColor = [UIColor clearColor];
    titleLabel.tag = 72;
    [self removeReusedLabel:mCell tag:72];
    [mCell addSubview:titleLabel];
}

-(void)removeReusedLabel:(MagazineCell *)mCell tag:(int)tag {
    UILabel *foundLabelBackground = (UILabel *)[mCell viewWithTag:tag];
    if (foundLabelBackground) [foundLabelBackground removeFromSuperview];
}

干杯——杰里克

【问题讨论】:

  • 您的单元格类型是什么:storyBoard 单元格、Xib 或仅代码?
  • Storyboard,用 imageview 和 label 配置单元格。

标签: objective-c xcode uilabel uicollectionview uicollectionviewcell


【解决方案1】:

发生这种情况是因为细胞重复使用。如果要像这样添加标签,则应检查从 dequeue 方法获得的单元格上是否有标签,如果存在则将其删除。您可以给标签一个标签,然后使用 viewWithTag: 查看标签是否存在,然后让它调用 removeFromSuperview。我没有对此进行测试,但我认为这样的事情应该可以工作:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
    UILabel *foundLabel = [mCell viewWithTag:47];
    if (foundLabel) [foundLabel removeFromSuperview];
    .......

记得在 cellTitle:indexPath 方法中创建标签时将标签的标签设置为相同的数字。顺便说一句,您应该将此标签添加到单元格的 contentView 而不是单元格本身。

编辑后:

使用 viewWithTag 对您的代码进行的这种修改对我来说效果很好:

-(CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGSize cellSize = [self.magazineLayout[indexPath.item] size];
    return cellSize;
}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    MagazineCell *mCell = (MagazineCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"RDCell" forIndexPath:indexPath];
    mCell.backgroundColor = [UIColor lightGrayColor];
    if ([mCell viewWithTag:47]) [[mCell viewWithTag:47] removeFromSuperview];
    UIImage *image = self.magazineLayout[indexPath.item];
    mCell.imageView.image = image;

    NSString *title = [[NSString alloc] initWithFormat:@"Image %@", self.data[indexPath.item]];
    [mCell addSubview:[self cellTitle:title indexPath:indexPath]];

    return mCell;
}


-(UILabel *)cellTitle:(NSString *)name indexPath:(NSIndexPath *)indexPath {
    CGSize itemSize = [self.magazineLayout[indexPath.item] size];
    int top = itemSize.height - 40;
    int width = itemSize.width;
    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(0, top, width, 40)];
    title.textColor = [UIColor blackColor];
    title.text = name;
    title.backgroundColor = [UIColor whiteColor];
    title.alpha = 0.5f;
    title.tag = 47;
    return title;
}

在本例中,数组 magazineLayout 填充了 16 张不同大小的图片。

不过,更简单的方法是将标签添加到情节提要(或 xib)中的自定义单元格。如果您将其固定在侧面和底部,并将其高度设置为 40,您将获得所需的内容,而无需创建标签或检查其存在的代码。

【讨论】:

  • 工作。但现在我无法更改标签的大小和位置。在(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath 我执行以下操作:UILabel *titleLabel = (UILabel *)[mCell viewWithTag:105]; [self labelPosition:titleLabel indexPath:indexPath];labelPosition 这:CGRect position = CGRectMake(0, top, width, 40); titleLabel.frame = position; 但没有效果
  • 无法使用viewWithTag 找到解决方案并重新定位标签。但我找到了另一种解决方法,请参阅我在 Workaround Solution 的初始帖子
  • 再次尝试了您的解决方案。不工作。我认为这是因为,重复使用的单元格内部并不总是具有相同的标签,如果它们被使用的话。例如。标签 47 不存在于重复使用的单元格中,但标签 48. 48 不会被删除,因此它会显示出来,我得到了奇怪的结果。如果我只删除所有子视图 for (UIView *subview in self.subviews) {[subview removeFromSuperview];} 它工作正常。
  • @jerik 我不知道为什么它对你不起作用,但如果你在情节提要中将标签设置为 47,每个单元格都会有这个标签——它永远不会是 48。
  • 好的。知道我明白。我为每个单元格创建了一个不同的标签。那是我的误解。我将使用一个 (!) 标记对其进行测试以供重复使用。
【解决方案2】:

我知道答案已被接受并关闭。但是以防万一有人偶然发现这个线程,避免这个问题的正确方法是继承 UICollectionViewCell 然后使用

[self.collectionView registerClass:[LPCollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];

在子类的 initWithFrame 方法中初始化所有元素

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        self.lblName = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 95.0, 106.0, 20)];
        self.lblName.text = @"";
        self.lblName.textAlignment = NSTextAlignmentCenter;
        [self.lblName setFont:[UIFont fontWithName:@"GothamRounded-Bold" size:10]];
        [self.lblName setTextColor:[UIColor colorWithRed:137.0f/255.0 green:137.0f/255.0 blue:137.0f/255.0 alpha:1.0]];
        [self.lblName setBackgroundColor:[UIColor clearColor]];
        [self addSubview:self.lblName];
}

将元素公开,以便稍后在集合视图数据源调用中对其进行访问。

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    LPCollectionViewCell *cell = (LPCollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
    cell.backgroundColor = [UIColor whiteColor];
    [cell.lblName setText:@"This is awesome"];
}

就是这样!

【讨论】:

  • 非常感谢。将此与 sizeForItemAtIndexPath 结合起来效果很好!
猜你喜欢
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-05
相关资源
最近更新 更多