我有一个UITableViewCell,它有两个UITextFields(没有边框)。以下约束用于设置水平布局。
@"|-10-[leftTextField(>=80)]-(>=10)-[rightTextField(>=40)]-10-|"
没有什么花哨的,并且按预期工作。
如您所见,上面的textField具有正确的大小。较低的textField以空文本开头,由于空文本,它是80点宽。当我在编辑textField中键入文本时,文本向左滚动,它不会改变其宽度。
我不喜欢这样,当用户键入textField时,textField的宽度应该调整。
在我看来,应该开箱即用。通过为IBAction
事件实施UIControlEventEditingChanged
,我可以确认输入实际上更改了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));
}
有人知道我错过了什么吗?我有什么办法让这项工作成功?
答案 0 :(得分:58)
这对我有用:
- (IBAction) textFieldDidChange: (UITextField*) textField
{
[UIView animateWithDuration:0.1 animations:^{
[textField invalidateIntrinsicContentSize];
}];
}
有趣的是,考虑到text from the docs,它似乎应该开箱即用:
此外,如果视图的属性发生更改并且该更改会影响 内在的内容大小,视图必须调用 invalidateIntrinsicContentSize,以便布局系统注意到 改变并可以重新布局。在您的视图类的实现中, 你必须确保,如果任何财产的价值 内在大小取决于你调用的变化 invalidateIntrinsicContentSize。 例如,文本字段调用 如果字符串值更改,则invalidateIntrinsicContentSize。
我最好的猜测是,文本字段仅在编辑完成后调用invalidateIntrinsicContentSize,而不是在编辑过程中。
编辑:一堆“这对我不起作用”。我认为这里的混淆可能是与textFieldDidChange:
处理程序绑定的触发事件。该事件需要是UIControlEventEditingChanged。如果您正在使用IB,请仔细检查您是否正在处理正确的事件。
UITextField
的大小也不受限制。您可以使用约束将其锁定到位,但任何宽度约束或左右定位约束集都将阻止其调整其内在内容大小。
答案 1 :(得分:19)
我不知道为什么UITextField
仅在intrinsicContentSize
重新启动其第一响应者状态时才更新intrinsicContentSize
。这适用于iOS 7和iOS 8。
作为临时解决方案,我覆盖typingAttributes
并使用leftView
确定大小。这也考虑了rightView
和// 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
}
{{1}}
在这里,我更广泛地考虑了插入符号
答案 2 :(得分:4)
这是斯威夫特的答案。作为奖励,如果有占位符,此代码段不会折叠文本字段。
InvalidOperationException
答案 3 :(得分:3)
首先要做的事情:在Swift 4中,UITextField的intrinsicContentSize是一个计算变量,而不是一个方法。
以下是具有专用用例的Swift4解决方案。右对齐文本字段可以调整大小并向左延伸到某个像素边界。
文本字段分配给 CurrencyTextField类,该类继承自 UITextField 。然后扩展CurrencyTextField以提供自定义行为,以返回对象的 intrinsicContentSize ,一个计算变量。
。
CurrencyTextField实例的“编辑已更改”事件将映射到其主机UIViewController类中的 repositionAndResize IBAction方法。此方法只是使CurrencyTextField实例的当前内在内容大小无效。调用CurrencyTextField的 invalidateIntrinsicContentSize 方法(继承形式为UITextField)会触发尝试获取对象的内在内容大小。
CurrencyTextField的intrinsicContentSize getter方法中的自定义逻辑必须将CurrentTextField的text属性转换为NSString,以确定其大小,如果CurrencyTextField的x坐标大于规定的像素边界,则返回为intrinsicContentSize。
class CurrencyTextField:UITextField {
}
extension CurrencyTextField {
override open var intrinsicContentSize: CGSize {
if isEditing {
let string = (text ?? "") as NSString
let stringSize:CGSize = string.size(withAttributes:
[NSAttributedStringKey.font: UIFont.systemFont(ofSize:
19.0)])
if self.frame.minX > 71.0 {
return stringSize
}
}
return super.intrinsicContentSize
}
}
class TestController: UIViewController {
@IBAction func repositionAndResize(_ sender: CurrencyTextField) {
sender.invalidateIntrinsicContentSize()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
答案 4 :(得分:1)
我对UITextView
有类似的要求(必须动态增加它的高度和其他一些东西)。
我所做的与此类似:
考虑self.contentView
是superview
textField
- (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));
}
另外,考虑到我的要求,我不得不覆盖updateConstraints
UITextView
的{{1}}方法。
如果您选择选择该解决方案(可能需要更精细的方法),您可以这样做:
superview
如前所述,我使用了覆盖选项,因为我需要一种更精细的调整方法。
此外,与往常一样,您需要确保检查您认为可能遇到的任何边缘情况(就调整值而言)。
希望这有帮助!
干杯!
答案 5 :(得分:1)
出于某种原因,调用invalidateIntrinsicContentSize
对我来说也不起作用,但由于边距和编辑控件,我也遇到了其他解决方案的问题。
此解决方案并不总是需要的;如果invalidateIntrinsicContentSize
有效,那么所有需要做的就是在文本更改时添加一个调用,就像在其他答案中一样。如果这不起作用,那么这里有一个解决方案(改编自here),我发现它也可以使用明确的控件:
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
is working by itself,这将最终重复计算更改,以便首先检查。
答案 6 :(得分:0)
另一个解决方案是将前导/尾随约束设置为textField,并使用isActive
打开/关闭它们。
编辑开始时,打开它们,如果文本居中,效果将是相同的(文本似乎会自动调整大小作为输入)。当编辑停止时,关闭约束,这将围绕文本包裹框架。
答案 7 :(得分:0)
对我来说,我还在文本字段中添加了一个目标(UIControlEventEditingChanged)
- (void)textFieldChanged:(UITextField *)textField {
[textField sizeToFit];
}
如果你有背景颜色,那么只需用委托方法更新它:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
textField.backgroundColor = [UIColor grayColor];
return YES;
}
答案 8 :(得分:0)
您可以在viewDidLoad中添加此代码以解决问题。
if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)])
{
self.edgesForExtendedLayout = UIRectEdgeNone;
}