【问题标题】:UITableView is lagging a cell containing a UITextView is displayed the first timeUITableView 滞后第一次显示包含 UITextView 的单元格
【发布时间】:2012-12-19 16:05:47
【问题描述】:

当特定单元格移动到超级视图时,我遇到了 UITableView 在滚动时滞后的问题。

我已经编写了自己的 IPFormKit,以便轻松创建具有不同类型 inputViews 的漂亮输入表单,而无需为每个表单字段/单元格手动重新编码。

我有一个 UITableViewController 来初始化我的 IPFormKit 及其字段。 - (UITableViewCell *) cellForRowAtIndexPath:(NSIndexPath)indexPath; 加载出列的自定义单元格(称为 IPFormTableViewCell)并将 IPFormField 分配给每个单元格。

自定义 UITableViewCell (IPFormTableViewCell) 在初始化时使用 CGRectZero 创建所有(可能)需要的 inputView(UITextField、UITextView、CustomUILabel)。

根据 IPFormField 的类型(已作为单元格的 iVar 初始化)匹配的 inputView 被调整大小并作为子视图添加到 cell.contentView 内。

- (UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath)indexPath

对于 UITextField 和 CustomUILabel,这可以完美运行,但是 当 inputView 是 UITextView 时,当第一次显示此单元格时,UITableView 的滚动会(略微)明显滞后.

当单元格在稍后滚动后再次显示时(即使单元格被重用,因此 UITextView 被删除和读取),没有延迟并且这些单元格的滚动非常流畅.

我想不出这种滞后的原因是什么。 任何想法都值得赞赏。

PS:延迟在 iPhone 4 和 iPhone 4S 上都很明显,并且持续时间几乎完全相同(因此它不应该与 CPU 相关)

UITableViewController.m:

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

- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *CellIdentifier = @"IPFormFieldCell";

    // Get Form Field for indexPath
    IPFormField *formField = [self.form fieldAtIndexPath:indexPath];

    IPTableViewCell *cell = (IPTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[[IPTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
        cell.backgroundView = nil;
        cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background.png"]];
        cell.selectedBackgroundView = nil;
        cell.selectionStyle = UITableViewCellSelectionStyleNone;
    }

    [cell assignFormField:formField];

    return cell;
}  

IPFormTableViewCell.m:

- (void)assignFormField:(IPFormField *)field:

- (void) assignFormField:(IPFormField *)field {
    if (formField != nil) {
        formField.inputView = nil; // unlink old field
    }

    self.formField = field;

    // Change Field Label
    [fieldLabel setText:[field label]];

    // Add an Input View to the Field
    UIView *labelView = nil;
    UIView *inputView = nil;

    switch (formField.type) {
        case IPFormFieldTypeTextField:
        {
            labelView = fieldLabel;

            UITextField *textField = inputTextField;
            textField.delegate = (IPFormTextField *)formField;
            textField.inputAccessoryView = [formField.form inputAccessoryView];
            textField.placeholder = [self.formField stringFromValue:self.formField.defaultValue];
            textField.keyboardType = [(IPFormTextField *)formField keyboardType];

            if (self.formField.value == nil || [[self.formField stringFromValue:self.formField.value] isEqualToString:[self.formField stringFromValue:self.formField.defaultValue]]) {
                textField.clearsOnBeginEditing = YES;
            } else {
                textField.text = [self.formField stringFromValue:self.formField.value];
                textField.clearsOnBeginEditing = NO;
            }

            inputView = textField;
            break;
        }

        case IPFormFieldTypeTextArea:
        {            
            UITextView *textView = inputTextView;
            textView.delegate = (IPFormTextArea *)formField;
            textView.inputAccessoryView = [formField.form inputAccessoryView];

            if (self.formField.value == nil || ![[self.formField stringFromValue:self.formField.value] length] > 0) {
                textView.text = [self.formField stringFromValue:self.formField.defaultValue];
            } else {
                textView.text = [self.formField stringFromValue:self.formField.value];
            }

            inputView = textView;
            break;
        }

        default:
            break;
    }

    self.leftItem = labelView;
    self.rightItem = inputView;

    if (leftItem != nil) {
        [self.contentView addSubview:leftItem];
    }

    if (rightItem != nil) {
        [self.contentView addSubview:rightItem];
    }

    formField.inputView = rightItem;
}

【问题讨论】:

  • 提供更多代码,可能是整个cellForRowAtIndexpath,以便我们确定问题所在。我猜,这里的问题与您的自定义控件有关。
  • 我已经添加了源代码,但是每次从 tableView 请求一个单元格时都会调用 - (void) assignFormField: 方法,所以这无法解释为什么它只有在单元格变得可见时才会滞后第一次。请注意,当单元格再次可见时它不会滞后,即使在此期间该单元格已被重用(因此之前的 inputView - UITextView 已从超级视图中删除)。

标签: objective-c ios uitableview scroll uitextview


【解决方案1】:

显然,我的数据源的cellForRowAtIndexPath: 使用了一个字段的属性,该属性设置为@property (nonatomic, copy) 而不是@property (nonatomic, readonly)

现在我已经修复了它,滚动不再滞后了。

【讨论】:

    【解决方案2】:

    正如我所猜测的,您的问题在于您的自定义控件。是的,您正在重用该单元格,但这并没有在您的情况下提供任何内容,因为每次您请求该单元格时,您都在为每个单元格创建新的自定义控件。我的建议是,您可以创建自定义控件并将其保留为实例变量,并在需要时返回它们而不需要很多 if-elses,或者,您可以为您的两种情况创建自定义单元格,并使用不同的单元格标识符保持它们出列并重用他们。祝你好运!

    【讨论】:

    • am 将 inputViews(UITextView、UITextField、CustomUILabel)存储在实例变量中。它们在 UITableViewCell 的 init 上使用 CGRectZero 进行分配和初始化。在 assignFormField: 方法中,我只是将表单字段分配为委托并设置 inputAccessoryView 和文本值。
    猜你喜欢
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多