UITableViewCell 中的最终 UIButton 是不可变的

Posted

技术标签:

【中文标题】UITableViewCell 中的最终 UIButton 是不可变的【英文标题】:Final UIButton in a UITableViewCell is unmutable 【发布时间】:2017-01-12 23:18:11 【问题描述】:

我有一个 UITableView(和关联的单元格),其中包含可变数量的项目。每个单元格内都有与正在显示的对象相关联的值。还有一个按钮允许用户说明正在显示的任务(来自对象属性)是否完成。它应该改变颜色并变得活跃。这有效,除了列表中的最后一项。这是不工作的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TasksItem"];
    [BAPAppDelegate setBorder:[cell viewWithTag:300] withBorder:[BAPAppDelegate darkGreyColor]];
    [BAPAppDelegate setBorder:[cell viewWithTag:301] withBorder:[UIColor blackColor]];
    [BAPAppDelegate setBorder:[cell viewWithTag:1000] withBorder:[UIColor blackColor]];
    ServiceRequest *sr = (mListTasks)[indexPath.row];
    [(UILabel *)[cell viewWithTag:110] setText:sr.vSRType];
    UILabel *smry = (UILabel *)[cell viewWithTag:301];
    smry.text = [NSString stringWithFormat:@"%@", [sr vMTSmry]];    // check if completed
    int cnt;
    int complete;
    UIButton* btn;
    cnt = [sr getBeforeRequired];
    complete = [sr getBeforeCompleted];
    markCompleteButton = YES;
    btn = (UIButton *)[cell viewWithTag:120];
    if (cnt > 0) 
        [btn setHidden:NO];
        [btn setTitle:[NSString stringWithFormat:@"%i", cnt] forState:UIControlStateNormal];
     else 
        [btn setTitle:@"0" forState:UIControlStateNormal];
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    cnt = [sr getDuringRequired];
    complete = [sr getDuringCompleted];
    btn = (UIButton *)[cell viewWithTag:121];
    if (cnt > 0) 
        [btn setHidden:NO];
        [btn setTitle:[NSString stringWithFormat:@"%i", cnt] forState:UIControlStateNormal];
     else 
        [btn setTitle:@"0" forState:UIControlStateNormal];
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    cnt = [sr getAfterRequired];
    complete = [sr getAfterCompleted];
    btn = (UIButton *)[cell viewWithTag:122];
    if (cnt > 0) 
        [btn setHidden:NO];
        [btn setTitle:[NSString stringWithFormat:@"%i", cnt] forState:UIControlStateNormal];
     else 
        [btn setTitle:@"0" forState:UIControlStateNormal];
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    cnt = [sr getCheckRequired];
    complete = [sr getCheckCompleted];
    btn = (UIButton *)[cell viewWithTag:123];
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [btn setImage:[UIImage imageNamed:@"check_red.png"] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
        [btn setImage:[UIImage imageNamed:@"check.png"] forState:UIControlStateNormal];
    
    btn = (UIButton *)[cell viewWithTag:1000];
    [btn setTag:indexPath.row + 1001];
    if (markCompleteButton) 
        [btn setBackgroundColor:[BAPAppDelegate greenColor]];
        [btn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [btn setEnabled:YES];
        [btn setTitle:@"YEP" forState:UIControlStateNormal];
        NSLog(@"YEP %ld", (long)indexPath.row);
     else 
        [btn setEnabled:NO];
        NSLog(@"NOPE %ld", (long)indexPath.row);
    
    [cell prepareForReuse];
    return cell;

正如预期的那样,日志显示“YEP 8”,但按钮本身没有任何变化。列表中前面的其他按钮按预期显示并执行其操作。

任何见解将不胜感激!

【问题讨论】:

需要更多上下文(更多代码)来帮助,但作为一个疯狂的猜测,它是屏幕外的第 8 个单元格?如果是这样,我怀疑它正在被重用,并且它的状态与您期望的不一样。看看 UITableViewCell prepareForReuse 方法。 没有更多的代码可以添加,坦率地说,这是一个非常枯燥的实现,这就是我如此困惑的原因。但是,它确实在首屏下方,因此确实需要滚动到其他正常工作的位置。我将编辑我的代码片段以提供一些额外的上下文。 【参考方案1】:

我最终将 UITableViewCell 子类化并将 UITableViewCell 从我的故事板连接到我的子类,然后将按钮的插座连接到子类。此外,我将按钮的操作设置为转到子类。

TasksCell.h

@protocol TasksCellDelegate <NSObject>
- (void)buttonPressed:(UIButton *)sender;
@end

@interface TasksCell : UITableViewCell
@property (weak, nonatomic) id<TasksCellDelegate> delegate;
@property (weak, nonatomic) IBOutlet UIButton *button;

- (IBAction)buttonPressed:(UIButton *)sender;
@end

TasksCell.m:

#import "TasksCell.h"

@implementation TasksCell
- (id)initWithFrame:(CGRect)frame 
    self = [super initWithFrame:frame];
    if (self) 
        // Initialization code
    
    return self;


- (IBAction)buttonPressed:(UIButton *)sender 
    [self.delegate buttonPressed:sender];

@end

TasksViewController.h

#import "TasksCell.h"

TasksViewController.m:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
    TasksCell *cell;
    cell = [tableView dequeueReusableCellWithIdentifier:@"TasksItem"
                                           forIndexPath:indexPath];
    [BAPAppDelegate setBorder:[cell viewWithTag:300] withBorder:[BAPAppDelegate darkGreyColor]];
    [BAPAppDelegate setBorder:[cell viewWithTag:301] withBorder:[UIColor blackColor]];
    [BAPAppDelegate setBorder:[cell viewWithTag:1000] withBorder:[UIColor blackColor]];
    ServiceRequest *sr = (mListTasks)[indexPath.row];
    [(UILabel *)[cell viewWithTag:110] setText:sr.vSRType];
    UILabel *smry = (UILabel *)[cell viewWithTag:301];
    smry.text = [NSString stringWithFormat:@"%@", [sr vMTSmry]];    // check if completed
    int cnt;
    int complete;
    UIButton* btn;
    cnt = [sr getBeforeRequired];
    complete = [sr getBeforeCompleted];
    markCompleteButton = YES;
    btn = (UIButton *)[cell viewWithTag:120];
    if (cnt > 0) 
        [btn setHidden:NO];
        [btn setTitle:[NSString stringWithFormat:@"%i", cnt] forState:UIControlStateNormal];
     else 
        [btn setTitle:@"0" forState:UIControlStateNormal];
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    cnt = [sr getDuringRequired];
    complete = [sr getDuringCompleted];
    btn = (UIButton *)[cell viewWithTag:121];
    if (cnt > 0) 
        [btn setHidden:NO];
        [btn setTitle:[NSString stringWithFormat:@"%i", cnt] forState:UIControlStateNormal];
     else 
        [btn setTitle:@"0" forState:UIControlStateNormal];
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    cnt = [sr getAfterRequired];
    complete = [sr getAfterCompleted];
    btn = (UIButton *)[cell viewWithTag:122];
    if (cnt > 0) 
        [btn setHidden:NO];
        [btn setTitle:[NSString stringWithFormat:@"%i", cnt] forState:UIControlStateNormal];
     else 
        [btn setTitle:@"0" forState:UIControlStateNormal];
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
    
    cnt = [sr getCheckRequired];
    complete = [sr getCheckCompleted];
    btn = (UIButton *)[cell viewWithTag:123];
    if (complete < cnt) 
        [btn setTitleColor:[BAPAppDelegate redColor] forState:UIControlStateNormal];
        [btn setImage:[UIImage imageNamed:@"aprsi_check_red.png"] forState:UIControlStateNormal];
        [self markComplete:NO];
     else 
        [btn setTitleColor:[BAPAppDelegate greenColor] forState:UIControlStateNormal];
        [btn setImage:[UIImage imageNamed:@"aprsi_check.png"] forState:UIControlStateNormal];
    
    [cell.button setTag:indexPath.row + 1001];
    if (markCompleteButton) 
        cell.button.backgroundColor = [BAPAppDelegate greenColor];
        [cell.button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [cell.button setEnabled:YES];
        NSLog(@"YEP %ld", (long)indexPath.row);
     else 
        [cell.button setTitleColor:[BAPAppDelegate darkGreyColor] forState:UIControlStateDisabled];
        [cell.button setBackgroundColor:[BAPAppDelegate lightGreyColor]];
        [cell.button setEnabled:NO];
        NSLog(@"NOPE %ld", (long)indexPath.row);
    
    [cell prepareForReuse];
    return cell;

为了让按钮按预期工作,我将按钮委托保留在 TasksViewController 中,但同样可以轻松地将其移至子类。希望这可以帮助某人!

【讨论】:

以上是关于UITableViewCell 中的最终 UIButton 是不可变的的主要内容,如果未能解决你的问题,请参考以下文章

动态添加和删除 UITableViewCells 到 UITableView

在 UITableViewCell 中检测具有灵活宽度的视图的最终布局大小

UITableViewCell 子类,在代码中绘制,动画中的删除按钮

在 UITableViewCell 中调整 UITextView 的大小

跨各种 UITableViews 的 UITableViewCell 原型单元格

UITableViewCell - 在动态表格视图中获取 UITextField 值