0

抬头编辑:我在下面发布了(简单)答案。无需浪费时间查看所有这些代码。另请参阅杰克劳伦斯的回答中的结构建议。


我在 tableViewCell 中设置了一个 UITextField,它以enabled = NO. 后来它被更改为,enabled = YES以便它可以成为第一响应者并调用键盘等。

但是一旦enabled是NO,它就再也不会是YES了:

tf.enabled = YES;
printf(" Is tf enabled? %d", [tf isEnabled]); // this prints 0 — it refuses to be re-enabled.

更奇怪的是,如果我继承 UITextField 并给它一个简单的自定义方法,我可以从控制器成功调用该方法——之前 enabled设置为 NO。一旦enabled为否,调用自定义方法什么也不做。没有警告或异常;它只是不运行。

所以问题不仅仅是响应者链的一些问题。曾经禁用的文本字段的行为就像一个黑洞。

enabled我确实看过 Apple 的单元格中可编辑文本字段的演示,“TaggedLocations”,他们完全不受惩罚地摆弄:nameField.enabled = NO;一切都nameField.enabled = YES;像发条一样。

还有另一条线索:UIControl 类引用说:“如果启用状态为 NO,则控件会忽略触摸事件,子类可能会以不同方式绘制。” 但是拒绝重新启用?拒绝接受方法调用?我不明白。


好吧,这可能比你真正想看的要多,但希望其中隐藏着一些线索。

下面是 UITextField 子类的 h 和 m 文件:

#import "FooNameFieldForCell.h"

@implementation FooNameFieldForCell

- (BOOL) canBecomeFirstResponder {
    printf("\nCBFR called, self.enabled is %d.", self.enabled); 
    if (self.enabled)
        return YES;
    else
        return NO;
}

- (BOOL) canYouHearMe:(id)sender {
    printf("Yes, I hear you."); 
    return YES;
}

@end

#import <UIKit/UIKit.h>

@interface FooNameFieldForCell : UITextField {

}

- (BOOL) canYouHearMe:(id)sender;

@end

这是 cellForRow 和操作方法:

BOOL bPortrait = UIInterfaceOrientationIsPortrait(self.interfaceOrientation);

// Cell Which Layout
NSString *identifier = nil;
UITableViewCell *cellFooList = nil;
switch (indexPath.row) {
    case 0:
        // this textfield is in row 0
        identifier = bPortrait ? @"cellFooListName_portrait" : @"cellFooListName_landscape";
        cellFooList = [tableView dequeueReusableCellWithIdentifier:identifier];
        if (!cellFooList)
            cellFooList = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease];
        break;
    // other rows…
}

// Foo
Foo *Foo = [self.frcFoosAllReg_byName.fetchedObjects objectAtIndex:indexPath.section];

// Cell Fill
switch (indexPath.row) {
    case 0: {
        if (cellFooList.tag == 1) {
            for (UIView *subview in cellFooList.subviews) {
                if (subview.tag == 2) {
                    ((FooNameFieldForCell *)cellFooList).text = Foo.FooName;
                    break;
                }
            }
            break;// dequeued cell, already done 
        }

        // button "Edit"
        // (Yes, I know you’re supposed to put this on the navBar, but as a user I have never liked that metaphor. I’m doing the editability by section/row.) 
        UIButton *btnEditFooName = [UIButton buttonWithType:UIButtonTypeRoundedRect];
        [btnEditFooName addTarget:self action:@selector(presentEditFooName:) forControlEvents:UIControlEventTouchUpInside]; // the selector is where I’m trying to enable the textfield
        // do button setup & framing
        [btnEditFooName setFrame:rectBtnEditFooName];
        [cellFooList.contentView addSubview:btnEditFooName];

        // TEXTFIELD SETUP FOLLOWS   

        // do framing
        FooNameFieldForCell *tfFooName = [[FooNameFieldForCell alloc] initWithFrame:rectFooName]; 
        [tfFooName canYouHearMe:self]; // custom method runs OK here
        tfFooName.text = Foo.FooName;
        tfFooName.enabled = NO;
        tfFooName.tag = 2; // tag to locate among cell's subviews
        [cellFooList.contentView addSubview:tfFooName];
        [tfFooName release];
        // no row selection allowed
        cellFooList.selectionStyle = UITableViewCellSelectionStyleNone;
        // tag as done
        cellFooList.tag = 1;
        break;
    // other cases…
    }
}
return cellFooList;
}

// Called by the Edit button:
- (void) presentEditFooName:(id)sender {

    // Determine which Foo is associated with sender.
    if (![sender isKindOfClass:[UIButton class]])
        return;
    UIView *cell = ((UIButton *)sender).superview.superview;
    if (!cell || ![cell isKindOfClass:[UITableViewCell class]])
        return;
    NSIndexPath *indexPath = [self.tvFooList indexPathForCell:((UITableViewCell *)cell)];
    Foo *Foo = [self.frcFoosAllReg_byName.fetchedObjects objectAtIndex:indexPath.section];

    FooNameFieldForCell *tfFooName = nil;
    for (UIView *subview in cell.subviews) {
        if (subview.tag == 2) {
            tfFooName = subview;
            break;
        }
    }

    // BLACK HOLE
        // because tfFooName is nil. But why? It shows up in the cell.

    tfFooName.enabled = YES; 
    [tfFooName becomeFirstResponder];
    printf("\ntfFooName can become firstResp? %d", tfFooName.canBecomeFirstResponder); // always prints 0, can't be firstResp
    [tfFooName canYouHearMe:self]; // does not run
    printf(" Is tfFooName enabled? %d", [tfFooName isEnabled]); // prints 0, still disabled

}

好吧,我的神秘黑洞竟然是——空!好的,现在看起来很明显,特别是因为objective-c 允许调用null。但是我还有另一个谜团:该字段的文本出现在单元格中,那么它怎么可能是 nil 呢?

4

3 回答 3

1

文本字段本身不是零 - 你是对的,如果它是零,它就不会显示在单元格中。相反,我认为这段代码没有找到单元格:

FooNameFieldForCell *tfFooName = nil;
for (UIView *subview in cell.subviews) {
    if (subview.tag == 2) {
        tfFooName = subview;
        break;
    }
}

插入断点并tfFooName在 for 循环之后或 if 语句内打印值以进行检查。

考虑使用以下方法之一,而不是搜索子视图或超级视图:

  • 使用 Objective-C 运行时的关联对象函数将 NSIndexPath 与编辑按钮相关联,并使用该索引路径检索单元格。
  • 使用键值观察将文本字段的文本值“绑定”到对象的值(小心单元重用和核心数据对象错误)
  • 创建一个子类UIButton并添加一个 indexpath 属性(有点乱)
  • 将基于块的事件处理添加到UIButton(最困难但最棒的,但那里有教程和预构建的解决方案),只需准确设置您想要在-tableView:cellForRowAtIndexPath:.
于 2012-08-24T03:18:34.820 回答
0

有时,如果在这种情况下设置对象的属性时遇到问题,向对象添加公共方法会有所帮助,例如:

-(void) setEnabledToYes
{
self.enabled=YES;
}

我知道这是一个陪审团解决方案,但它以前对我有用

于 2012-08-24T03:05:16.657 回答
0

像往常一样,当我把头发扯掉时,黑洞之谜原来很简单。

这...

FooNameFieldForCell *tfFooName = nil;
for (UIView *subview in cell.subviews) {
    if (subview.tag == 2) {
        tfFooName = subview;
        break;
    }
}

...应该是这样的:

FooNameFieldForCell *tfFooName = nil;
for (UIView *subview in ((UITableViewCell *)cell).contentView.subviews) {
    if (subview.tag == 2) {
        tfFooName = subview;
        break;
    }
}

自定义视图在单元格的contentView中向下一层,而不是其直接子视图。啊!浪费了这么多时间!

于 2012-08-24T03:37:43.377 回答