修改 UICollectionView 中特定单元格中的 UIButton

Posted

技术标签:

【中文标题】修改 UICollectionView 中特定单元格中的 UIButton【英文标题】:Modify UIButton in specific cell in UICollectionView 【发布时间】:2014-04-03 11:34:10 【问题描述】:

我整天都在努力寻找我的问题出现的原因。

我有一个UICollectionView,其中的单元格包含UIButtons 和其他UIViews。

我的UICollectionView 有 8 个部分。

我想在点击特定单元格时修改UIButton 的图像。

我触发了一个名为“checked”的方法来修改图像。

但不是只修改特定按钮的图像,而是修改其他单元格中的其他按钮。当我按下这些其他按钮之一时,它们都再次变为“未选中”。所以,它们是联系在一起的,但我真的不知道为什么!

这是我的代码:

- (ExCell*) collectionView:(UICollectionView *)collectView cellForItemAtIndexPath:(NSIndexPath *)indexPath 

    //create collection view cell
    ExCell *cell = (ExCell *)[collectView dequeueReusableCellWithReuseIdentifier:@"ExCell" forIndexPath:indexPath];

    // the index is the row number in section + the number of items in all previous sections
    int index = (int)indexPath.row;
    for(int k=0; k < indexPath.section ; k++)
        index += nbItemsInPart[k];
    
    //configure cell :
    NSMutableString *text = [[NSMutableString alloc]initWithString:@"Practical Exercise "];
    [text appendString:[NSString stringWithFormat:@"%d",index+1]];
    [text appendString:@"\n"];
    [text appendString:[titles objectAtIndex:index]];
    cell.label.text = text;
    [cell.reminder addTarget:self action:@selector(doSomething:) forControlEvents: UIControlEventTouchUpInside];
    [cell.done addTarget:self action:@selector(checked:) forControlEvents:UIControlEventTouchUpInside];
    [cell.doIt addTarget:self action:@selector(doExercise:) forControlEvents: UIControlEventTouchUpInside];
    [cell.doIt setTag:index];
    [cell setTag:indexPath.section];

    // return the cell
    return cell;

这是点击按钮时调用的方法(它有效,但结果会影响其他附加按钮...):

-(void)checked:(id)sender
    if([sender imageForState:UIControlStateNormal] == [UIImage imageNamed:@"checked.png"])
        [sender setImage:[UIImage imageNamed:@"unchecked.png"] forState:UIControlStateNormal];
     else
         [sender setImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
     

这是我的自定义单元格的实现:

@implementation ExCell
@synthesize imageView;
@synthesize label;
@synthesize reminder;
@synthesize done;
@synthesize doIt;

- (id)initWithFrame:(CGRect)aRect

    self = [super initWithFrame:aRect];
    
        CGRect screenBound = [[UIScreen mainScreen] bounds];
        CGSize screenSize = screenBound.size;
        CGFloat screenWidth = screenSize.width;
        CGFloat screenHeight = screenSize.height;

        done = [UIButton buttonWithType:UIButtonTypeCustom];
        done.frame = CGRectMake(0, 0, 85, 112);
        [done setImage:[UIImage imageNamed:@"unchecked.png"] forState:UIControlStateNormal];
        [self addSubview:done];

        float widthLabel = 0.0f;
        UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
        if(UIInterfaceOrientationIsPortrait(interfaceOrientation))
            widthLabel = (screenWidth-6)-158-156-3-85;
        else if(UIInterfaceOrientationIsLandscape(interfaceOrientation))
            widthLabel = (screenHeight-24)-158-156-3-85;
        
        //we create the UIImageView in this overwritten init so that we always have it at hand.
        imageView = [[UIImageView alloc] init];
        imageView.opaque = YES;
        imageView.frame = CGRectMake(86, 0, widthLabel, 112);
        [imageView setBackgroundColor:[UIColor whiteColor]];
        imageView.alpha = 0.7;
        imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
        //set specs and special wants for the imageView here.
        [self addSubview:imageView]; //the only place we want to do this addSubview: is here!

        label = [[UILabel alloc]initWithFrame:CGRectMake(90, 0, widthLabel-5, 112)];
        [label setBackgroundColor:[UIColor clearColor]];
        label.userInteractionEnabled = NO;
        label.numberOfLines = 0;
        [self addSubview:label];

        widthLabel = widthLabel+85+2;

        doIt = [UIButton buttonWithType:UIButtonTypeCustom];
        doIt.frame = CGRectMake(widthLabel, 0, 156, 112);
        doIt.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
        [doIt setImage:[UIImage imageNamed:@"faireExo.png"] forState:UIControlStateNormal];
        [self addSubview:doIt];

        widthLabel = widthLabel+1+156;

        reminder = [UIButton buttonWithType:UIButtonTypeCustom];
        reminder.frame = CGRectMake(widthLabel, 0, 158, 112);
        reminder.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
        [reminder setImage:[UIImage imageNamed:@"rappel.png"] forState:UIControlStateNormal];
        [self addSubview:reminder];

    
    return self;

@end

【问题讨论】:

当您说其他按钮受到影响时,您是在滚动后看到这些,还是在同一个视图中出现多个检查图像而没有滚动?如果是前者,这可能是单元重用的结果。此外,您不应使用“==”确定两个图像的等价性,而应使用 isEqual:。 滚动后我看到了其他按钮。 嗯,那肯定是单元重用的结果。你想要什么行为?您是否只想要一个带有已选中图像的单元格(因此,如果您单击另一个单元格,它会检查那个单元格并取消选中已选中的那个)? 我用 isEqual 替换了 == 如你所说。问题仍然存在...我注意到以下内容: UIButtons 会更改其图像,尽管它们不应该分别位于单独的部分中。我的意思是:当点击一个按钮时,每个部分会同时触发一个按钮。我不明白,因为我所做的是将方法单独分配为每个按钮的目标,然后修改给定按钮的图像。 我只想更改按钮被点击的单元格的按钮图像(“选中”,如果它是“未选中”,反之亦然)(仅针对该精确行和部分) 【参考方案1】:

由于单元格重用,您无法通过在按钮的操作方法中设置图像来做到这一点。相反,您应该有一个可变数组来跟踪要检查图像的单元格的 indexPaths。您在按钮的操作方法中从数组中添加(或删除)这些路径,但实际上您根据数组中的索引路径在 cellForItemAtIndexPath 中设置图像。这个例子是针对表格视图的,但是对于集合视图的过程是相同的。

@property (strong,nonatomic) NSMutableArray *checkedPaths; // I instantiate this in viewDidLoad

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 

    RDCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    [cell.button addTarget:self action:@selector(customActionPressed:) forControlEvents:UIControlEventTouchUpInside];
    if ([self.checkedPaths containsObject:indexPath]) 
        [cell.button setImage:[UIImage imageNamed:@"checked.png"] forState:UIControlStateNormal];
    else
        [cell.button setImage:[UIImage imageNamed:@"unchecked.png"] forState:UIControlStateNormal];
    
    return cell;




-(void)customActionPressed:(UIButton *) sender 
    id superView = sender.superview;
    while (superView && ![superView isKindOfClass:[UITableViewCell class]]) 
        superView = [superView superview];
    // this while loop finds the cell that the button is a subview of


    NSIndexPath *selectedPath = [self.tableView indexPathForCell:(UITableViewCell *)superView];
    if ([self.checkedPaths containsObject:selectedPath]) 
        [self.checkedPaths removeObject:selectedPath];
    else
        [self.checkedPaths addObject:selectedPath];
    

    [self.tableView reloadRowsAtIndexPaths:@[selectedPath] withRowAnimation:UITableViewRowAnimationAutomatic]; // you would use reloadItemsAtIndexPaths: for a collection view

【讨论】:

嗨@rdelmar,您是否知道如何从 uibutton(嵌入在 uicollectionviewcell 中)获取气泡点击事件并让 uicollectionview 处理点击?问题:***.com/questions/37335646/…【参考方案2】:

这解决了问题!我不得不打电话给 [collectionview reloadData] :

-(void)checked:(id)sender
    UIButton *button = (UIButton *)sender;
    NSNumber *indice = [NSNumber numberWithInt:(int)button.tag];
    if ([self.checkedPaths containsObject:indice])
        [self.checkedPaths removeObject:indice];
    else
        [self.checkedPaths addObject:indice];
    
    [collectionView reloadData];

非常感谢!!

【讨论】:

以上是关于修改 UICollectionView 中特定单元格中的 UIButton的主要内容,如果未能解决你的问题,请参考以下文章

如何在 willDisplay 单元格回调中访问 UICollectionView 中的特定单元格

无法在 uicollectionview、UICollectionView 的特定 indexPath.row 处为单元格设置标题

在 UICollectionView 中为特定单元格设置动画

页面加载时滚动后如何访问 UICollectionView 中的特定单元格?

如何将 UIAlertController 操作表锚定到特定单元格 UICollectionView?

如何使用 viewForSupplementaryElementOfKind 显示 UICollectionView 的特定单元格 - swift