在input时调整UITextField的大小(使用Autolayout)

我有一个UITableViewCell有两个UITextFields(无边框)。 以下约束用于设置水平布局。

@"|-10-[leftTextField(>=80)]-(>=10)-[rightTextField(>=40)]-10-|"

没有什么奇特的,并按预期工作。

在这里输入图像说明

正如你可以看到上面的textField具有正确的大小。 下面的文本字段以空文本开始,由于空文本,它是80点宽。 当我在编辑文本字段中input文本时,文本向左滚动,但不会改变其宽度。

我不喜欢,textField的宽度应该调整,而用户键入该文本字段。

在我看来,应该开箱即用。 通过为UIControlEventEditingChanged事件实现一个IBAction ,我可以确认打字实际上改变了UITextField的intrinsicContentSize

但是,宽度不会改变,直到textField不再是第一响应者。 如果我把光标放到另一个textField中,编辑后的textField的宽度就被设置了。 我想要的东西有点迟了

这些评论出来的线是我没有任何成功的尝试:

 - (IBAction)textFieldDidChange:(UITextField *)textField { [UIView animateWithDuration:0.1 animations:^{ // [self.contentView removeConstraints:horizontalConstraints]; // [self.contentView addConstraints:horizontalConstraints]; // [self.contentView layoutIfNeeded]; // [self.contentView setNeedsLayout]; // [self.contentView setNeedsUpdateConstraints]; }]; NSLog(@"%@", NSStringFromCGSize(textField.intrinsicContentSize)); } 

有人知道我错过了什么吗? 我可以尝试做什么?

这对我有用:

 - (IBAction) textFieldDidChange: (UITextField*) textField { [UIView animateWithDuration:0.1 animations:^{ [textField invalidateIntrinsicContentSize]; }]; } 

有趣的是,它看起来好像它应该开箱即用, 从文档中得到这个文本 :

另外,如果视图的属性发生更改,而且更改影响内在内容大小,则视图必须调用invalidateIntrinsicContentSize,以使布局系统注意到更改并可以重新布局。 在实现视图类时,必须确保如果内部大小所依赖的任何属性的值发生变化,则调用invalidateIntrinsicContentSize。 例如,如果string值更改,则文本字段将调用invalidateIntrinsicContentSize。

我最好的猜测是,一旦编辑完成,textfield只调用invalidateIntrinsicContentSize,而不是在期间。

编辑:一堆“这不适合我”。 我认为这里的混乱可能是与textFieldDidChange:处理程序有关的触发事件。 该事件需要是UIControlEventEditingChanged。 如果您使用IB,请仔细检查您是否正在处理正确的事件。

UITextField也不能在大小上受到限制。 您可以使用约束将其locking到位置,但是任何宽度约束或左+右定位约束的设置都将阻止其调整为其内在内容大小。

我不知道为什么UITextField只会在它的第一个响应者状态下更新它的intrinsicContentSize 。 这发生在iOS 7和iOS 8上。

作为一个临时解决scheme,我重写intrinsicContentSize并使用typingAttributes确定大小。 这也解释了leftViewrightView

 // This method is target-action for UIControlEventEditingChanged func textFieldEditingChanged(textField: UITextField) { textField.invalidateIntrinsicContentSize() } override var intrinsicContentSize: CGSize { if isEditing { let string = (text ?? "") as NSString let size = string.size(attributes: typingAttributes) return CGSize(width: size.width + (rightView?.bounds.size.width ?? 0) + (leftView?.bounds.size.width ?? 0) + 2, height: size.height) } return super.intrinsicContentSize } 

在这里,我把它放大以便说明这个脱口而出

这是Swift的答案。 作为奖励,如果存在占位符,则此代码段不会折叠文本字段。

 // UITextField subclass override func awakeFromNib() { super.awakeFromNib() self.addTarget(self, action: #selector(textFieldTextDidChange), forControlEvents: .EditingChanged) } func textFieldTextDidChange(textField: UITextField) { textField.invalidateIntrinsicContentSize() } override func intrinsicContentSize() -> CGSize { if self.editing { let textSize: CGSize = NSString(string: ((text ?? "" == "") ? self.placeholder : self.text) ?? "").sizeWithAttributes(self.typingAttributes) return CGSize(width: textSize.width + (self.leftView?.bounds.size.width ?? 0) + (self.rightView?.bounds.size.width ?? 0) + 2, height: textSize.height) } else { return super.intrinsicContentSize() } } 

我有一个与UITextView类似的要求(必须dynamic增加它的高度和其他一些东西)。

我所做的是类似于这样的:

考虑到self.contentViewtextFieldsuperview

 - (IBAction)textFieldDidChange:(UITextField *)textField { //You can also use "textField.superview" instead of "self.contentView" [self.contentView setNeedsUpdateConstraints]; //Since you wish to animate that expansion right away... [UIView animateWithDuration:0.1 animations:^{ [self.contentView updateConstraintsIfNeeded]; }]; NSLog(@"%@", NSStringFromCGSize(textField.intrinsicContentSize)); } 

另外,考虑到我的要求,我不得不重写我的UITextViewsuperviewupdateConstraints方法。

如果你select这个解决scheme(也许是为了更好的调整方法),你可以这样做:

 - (void)updateConstraints { [super updateConstraints]; //Firstly, remove the width constraint from the textField. [self.myTextField removeConstraint:self.textFieldWidthConstraint]; self.textFieldWidthConstraint = nil; CGSize contentSize = self.myTextField.intrinsicContentSize; self.textFieldWidthConstraint = [NSLayoutConstraint constraintWithItem:self.myTextField attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:contentSize.width]; [self.myTextField addConstraint:self.textFieldWidthConstraint]; } 

如前所述,我使用覆盖选项,因为我需要一个更好的调整方法。

此外,一如既往,您需要确保您正在检查您认为可能遇到的任何边缘情况(根据大小值)。

希望这可以帮助!

干杯!

解决这个问题的另一个方法是设置textField的前导/尾随约束,并使用isActive打开/closures它们。

当编辑开始,打开它们,如果文本居中,效果将是相同的(文字将似乎是自动resize作为打字)。 编辑停止时,closures约束,这将约束文本框架。

对我来说,我也添加了一个目标文本字段(UIControlEventEditingChanged)

 - (void)textFieldChanged:(UITextField *)textField { [textField sizeToFit]; } 

如果你有一个背景颜色,那么只需在委托方法中更新它:

 - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string { textField.backgroundColor = [UIColor grayColor]; return YES; } 

你可以在viewDidLoad中添加这个代码来解决这个问题。

 if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)]) { self.edgesForExtendedLayout = UIRectEdgeNone; } 

出于某种原因,调用invalidateIntrinsicContentSize也不适用于我,但是由于边距和编辑控件,我也遇到了其他解决scheme的问题。

这个解决scheme并不总是需要的。 如果invalidateIntrinsicContentSize起作用,那么所有需要做的事情就是在文本被改变的时候添加一个调用,就像在其他答案中一样。 如果这不起作用,那么这里有一个解决scheme(改编自这里 ),我发现它也有一个明确的控制:

 class AutoResizingUITextField: UITextField { var lastTextBeforeEditing: String? override init(frame: CGRect) { super.init(frame: frame) setupTextChangeNotification() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setupTextChangeNotification() } func setupTextChangeNotification() { NotificationCenter.default.addObserver( forName: Notification.Name.UITextFieldTextDidChange, object: self, queue: OperationQueue.main) { (notification) in self.invalidateIntrinsicContentSize() } NotificationCenter.default.addObserver( forName: Notification.Name.UITextFieldTextDidBeginEditing, object: self, queue: OperationQueue.main) { (notification) in self.lastTextBeforeEditing = self.text } } override var intrinsicContentSize: CGSize { var size = super.intrinsicContentSize if isEditing, let text = text, let lastTextBeforeEditing = lastTextBeforeEditing { let string = text as NSString let stringSize = string.size(attributes: typingAttributes) let origSize = (lastTextBeforeEditing as NSString).size(attributes: typingAttributes) size.width = size.width + (stringSize.width - origSize.width) } return size } deinit { NotificationCenter.default.removeObserver(self) } } 

如果invalidateIntrinsicContentSize工作 ,则最终会对更改进行重复计算,以便首先进行检查。