【问题标题】:Strange display issue with UISwitch in a UITableViewUITableView 中 UISwitch 的奇怪显示问题
【发布时间】:2014-07-29 18:00:21
【问题描述】:

我正在使用以下代码将 UISwitch 添加到 UITableView 单元格,但遇到了一个奇怪的显示问题。问题似乎是因为我会定期自动刷新 TableView,从而重新创建 UISwitch。

图片最能说明正在发生的事情。

开头是这样的:

变成这样:

顶部开关被打开和关闭。进入此状态需要几分钟时间(带有黑色绒毛),但只要打开然后关闭 UISwitch,您就会发现问题。

这里是代码:-

static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

//Includes code that also adds a UITextView and a UIImageView, but these do not have issues.

UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectMake(10, 5.0, 60.0, 50.0)];
[switchView addTarget:self action:@selector(updateSwitchAtIndexPath:) forControlEvents:UIControlEventValueChanged];

[cell.contentView addSubview:switchView];

return cell;

【问题讨论】:

  • 这是在设备上还是在模拟器上?什么操作系统版本?
  • 这是在设备上,IOS7。 iPad Mini Retina,运行 iPhone 应用程序。
  • 这是一个“单元重用错误”的示例。您可能还注意到,当您将开关滚动到屏幕外时,它们会自行重置。
  • CrimsonChris - 这是框架或我的代码的错误吗?我还没有找到解决办法。
  • @Remixed123 这是您的代码的错误。请参阅我的答案以获取可能的解决方案。子类化UITableViewCell 是另一种可能的解决方案。

标签: ios objective-c uitableview uiswitch


【解决方案1】:

每次加载单元格时,您都会添加一个新开关。您所看到的是许多开关堆叠在一起。

此外,您为开关设置的目标操作不会像您的选择器名称所暗示的那样传递索引路径。当我不想对我的单元进行子类化时,我通常会使用此解决方案。 Getting data from a textfield inside a prototype uicollectionviewcell

可能的解决方案:使用关联对象来跟踪您的开关。

static NSString *kIndexPathKey = @"indexPathKey";
static NSString *kSwitchViewKey = @"switchViewKey"; 

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"Cell";
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        UISwitch *switchView = [[UISwitch alloc] initWithFrame:CGRectMake(10, 5.0, 60.0, 50.0)];
        [switchView addTarget:self action:@selector(switchValueChanged:) forControlEvents:UIControlEventValueChanged];
        [self addSwitchView:switchView toCell:cell];
    }

    UISwitch *switchView = [self switchViewForCell:cell];
    [self setIndexPath:indexPath onSwitch:switchView];
    switchView.on = [self isIndexPathSelected:indexPath];

    return cell;
}

- (void)addSwitchView:(UISwitch *)switchView toCell:(UITableViewCell *)cell {
    [cell.contentView addSubview:switchView];
    [cell setAssociatedObject:switchView forKey:kSwitchViewKey];
}

- (UISwitch *)switchViewForCell:(UITableViewCell *)cell {
    return [cell associatedObjectForKey:kSwitchViewKey];
}

- (void)switchValueChanged:(UISwitch *)sender {
    NSIndexPath *indexPath = [self indexPathOfSwitch:sender];
    [self setRowSelected:sender.isOn atIndexPath:indexPath];
    [self.delegate didSelectItem:[self itemAtIndexPath:indexPath] atIndexPath:indexPath selected:sender.isOn sender:self];
}

- (void)setIndexPath:(NSIndexPath *)indexPath onSwitch:(UISwitch *)switchView {
    [switchView setAssociatedObject:indexPath forKey:kIndexPathKey];
}

- (NSIndexPath *)indexPathOfSwitch:(UISwitch *)switchView {
    return [switchView associatedObjectForKey:kIndexPathKey];
}

@implementation NSObject (AssociatedObjects)

- (void)setAssociatedObject:(id)object forKey:(NSString *const)key {
    objc_setAssociatedObject(self, (__bridge const void *)(key), object, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (id)associatedObjectForKey:(NSString *const)key {
    return objc_getAssociatedObject(self, (__bridge const void *)(key));
}

@end

请注意,以上所有使用关联对象的操作都可以通过使用UITableViewCell 的自定义子类来完成。但是,子类化有很多优点。

组合 > 继承。

【讨论】:

  • 是的,我怀疑就是这种情况,任何建议。我应该创建一个实例来重用吗?
  • 这当然是问题所在。您可以创建一个实例以重用,也可以在添加新开关之前删除单元格的contentView 中的所有subviews - 您可以选择适合您的情况的任何方法,但我会选择后者。
  • 关于删除单元格内容视图中所有子视图的任何代码建议?谢谢:-)
  • @Remixed123 删除所有子视图感觉就像是一种 hack,它可能会导致比它解决的问题更多的问题。我用一个真实的例子更新了我的答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-15
  • 1970-01-01
  • 1970-01-01
  • 2018-03-09
  • 2012-01-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多