【问题标题】:UITextView subclass as delegate of itselfUITextView 子类作为自身的代表
【发布时间】:2012-10-31 11:30:11
【问题描述】:

假设我将UITextView 添加到我的UIView,并且我希望它在每次内容更改时更改其背景颜色。我可以通过成为UITextView 的代表并实施textViewDidChange 来做到这一点。

如果我经常使用这种行为,创建一个UITextView 子类是有意义的,我将其称为ColorSwitchingTextView。默认情况下,它应该包含颜色切换行为,因此任何UIView 都可以简单地添加它,而不是标准的UITextView,如果它想要这种行为。

如何检测 ColorSwitchingTextView 类中内容的变化?我不认为我可以做类似self.delegate = self 的事情。

总之,UITextView 子类如何知道其内容何时发生变化?

编辑 看来我可以使用self.delegate = self,但这意味着使用ColorSwitchingTextView 的UIViewController 也不能订阅通知。一旦我在视图控制器中使用switchingTextView.delegate = self,子类的行为就不再起作用了。任何解决方法?我正在尝试获得一个自定义的UITextView,否则它就像普通的UITextView一样工作。

【问题讨论】:

  • “我不认为我可以做类似 self.delegate = self”的事情,为什么不呢?它应该可以正常工作。
  • 好吧,我没有得到任何错误或任何东西,但是将 UITextView 子类设置为 UITextViewDelegate 似乎很奇怪 - 你确定这是正确的方法吗?到目前为止,我无法从 ColorSwitchingTextView 内部触发 textViewDidChange。
  • 我认为将对象的委托设置为自身不是一个好主意。即使它没有抛出任何错误,它也不理想。正确的方法是覆盖 UITextView 中调用textViewDidChange 的任何方法.. 不幸的是,它的私有代码似乎无法访问/被拒绝这样做.. 虽然不太确定最后一部分.. 需要更多挖掘
  • 是的 - 基于此线程 lists.apple.com/archives/Cocoa-dev/2009/Jul/msg01406.html,将委托设置为 self 似乎是个坏主意。而且,它无论如何都不起作用。
  • 当然可以,我这样做是为了使 UITextViews 和具有最大行数和/或字符数的字段

标签: objective-c ios cocoa-touch uiview uitextview


【解决方案1】:

在您的子类中,监听UITextViewTextDidChangeNotification 通知并在收到通知时更新背景颜色,如下所示:

/* 
 * When you initialize your class (in `initWithFrame:` and `initWithCoder:`), 
 * listen for the notification:
 */
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(myTextDidChange)
                                             name:UITextViewTextDidChangeNotification
                                           object:self];

...

// Implement the method which is called when our text changes:
- (void)myTextDidChange 
{
    // Change the background color
}

- (void)dealloc
{
    // Stop listening when deallocating your class:
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

【讨论】:

  • 你会如何快速做到这一点?
  • 可以使用通知如果您愿意,但如果您确实想使用代理,只需在封闭视图中执行即可。
  • “封闭视图”是什么意思?谢谢!
  • 斯威夫特版NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewControllerNAME.myTextDidChange), name: UITextViewTextDidChangeNotification, object: self)
  • Swift 5 版本:NotificationCenter.default.addObserver(self, selector: #selector(myTextDidChange), name: UITextView.textDidChangeNotification, object: self)
【解决方案2】:

最好从一开始就做正确的事情。

Apple 和 SOLID 的建议是子类化不是 UITextView,而是 UIView。在您的自定义 UIColorTextView 中,您将有成员 UITextView 作为子视图,而您的 UIColorTextView 将是它的代表。此外,您的 UIColorTextView 将拥有自己的委托,并将所需的委托回调从 UITextView 传递给它的委托。

我有一些这样的任务,不是使用 UITextView,而是使用 UIScrollView。

【讨论】:

  • 没错,只需子类化 UIView,它包含 UITextView 并创建一个“系统”——完美。
【解决方案3】:

在您的子类中,将self 添加为UITextViewTextDidChangeNotification 的观察者。

也就是说,我不同意正在进行的对话,即将 self 设置为代表是一个坏主意。对于这种特殊情况,当然可以,但这只是因为有更好的方法(UITextViewTextDidChangeNotification)。

【讨论】:

  • UITextView 特别是根本不可能。当然,一般来说,delegate=self 并不是一件坏事。解决方案很简单——你使用一个封闭的 UIView 作为委托——创建一个很好的系统。
【解决方案4】:

您可以使用 NSNotificationCenter。

在子类中将delegate设置为self(从未尝试过,但你说它有效),然后在你想要获取通知的视图控制器中,做

[[NSNotificationCenter defaultCenter] 
         addObserver:self 
         selector:@selector(textFieldDidBeginEditing:) 
         name:@"TextFieldDidNotification" object:nil];

在子类中:

NSDictionary *userInfo = [NSDictionary dictionaryWithObject:self forKey:@"textField"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TextFieldDidBeginEditingNotification" object:self userInfo:userInfo]

现在您还可以传递字典中的任何其他信息。

【讨论】:

  • 这会将 NSNotification 传递到 -(void)textFieldDidEndEditing:(UITextField *)textField 而不是 UITextField,如果您期望 UITextField 像普通委托调用那样,这可能会很糟糕。将类似这样的内容添加到方法的顶部以正确获取 UITextField。 if([textfield isKindOfClass:[NSNotification class]]){textField = textField.object}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
相关资源
最近更新 更多