【问题标题】:How to increase width of textfield according to typed text?如何根据键入的文本增加文本字段的宽度?
【发布时间】:2017-05-17 03:27:39
【问题描述】:

我需要根据其内容增加文本字段的宽度。当用户输入文本时,文本字段的大小应该会自动增加。我在此文本字段旁边有一个关闭 (X) 按钮。

我限制了文本字段和按钮,使文本字段在屏幕上居中,并且按钮与它相邻。 (文本字段应该是可编辑的,按钮应该是可点击的)

文本字段大小是这样的:

当我在其中输入文字时,大小应该会自动增加:

我怎样才能做到这一点?

【问题讨论】:

标签: ios swift autolayout uitextfield


【解决方案1】:

我们可以通过这样设置 UITextField 约束来轻松实现:

//在 Xcode 9.1、Swift 4 上测试

输出:

【讨论】:

    【解决方案2】:

    我认为这是一个比你必须修改宽度限制更好的解决方案:

    Resize a UITextField while typing (by using Autolayout)

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

    如果需要,您可以省略动画..

    编辑:这是一个示例项目:https://github.com/TomSwift/growingTextField

    【讨论】:

    • @LearnOpenGLES 检查您是否正在处理 UIControlEventEditingChanged 以及您的处理程序是否被每个键盘按键调用。还要检查您的 UITextField 的宽度是否受到限制。
    • 感谢您回复额外信息。我检查并在每次按键时调用处理程序,但在编辑完成之前没有任何变化,这也是默认行为。我见过的唯一解决方案是覆盖实际 UITextField 类的解决方案。你有我可以测试的工作演示吗?
    • 确认示例项目对我有用,但不幸的是,解决方案没有,即使是相同的事件。我不相信该领域的宽度受到限制,因为它仍然能够增长并推开其他视图,但我的布局也更复杂,很难确定。在我的情况下,我还必须覆盖内在内容大小:stackoverflow.com/a/43622411/1317564 你会得到我的支持,因为答案确实有效,只是在某些情况下由于某种原因不会。
    • 你注意到需要动画了吗?我正在另一个地方进行测试,仅此一项就足够了,并且它在没有动画的情况下对我有用。
    【解决方案3】:

    我解决了我的问题:将其用于文本字段,不要超出屏幕。

     func getWidth(text: String) -> CGFloat
    {
        let txtField = UITextField(frame: .zero)
        txtField.text = text
        txtField.sizeToFit()
        return txtField.frame.size.width
    }
    
    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool
    {
        let width = getWidth(textField.text!)
        if UIScreen.mainScreen().bounds.width - 55 > width
        {
            txtWidthOfName.constant = 0.0
            if width > txtWidthOfName.constant
            {
                txtWidthOfName.constant = width
            }
            self.view.layoutIfNeeded()
        }
        return true
    }
    

    Objective C 版本

    -(CGFloat)getWidth:(NSString *)text{
        UITextField * textField = [[UITextField alloc]initWithFrame:CGRectZero];
        textField.text = text;
        [textField sizeToFit];
        return textField.frame.size.width;
    }
    
    -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
    {
        if (self.textFieldName.isEditing == YES) {
            CGFloat width = [self getWidth:textField.text];
            if ([UIScreen mainScreen].bounds.size.width - 60 > width) {
                self.txtWidthOfName.constant = 0.0;
                if (width > self.txtWidthOfName.constant) {
                    self.txtWidthOfName.constant = width;
                }
                [self.view layoutIfNeeded];
            }
        }
        return YES;
    }
    

    【讨论】:

      【解决方案4】:

      答案都需要一堆代码,但你可以做任何界面构建器;无需代码。

      只需将 textField 嵌入 UIStackView 并将 stackView 限制为小于或等于其父视图减去一些常数(如果您愿意,也可以给它一个最小宽度)。 stackView 将负责始终使 textField 成为其固有大小,或 stackView 的 maxwidth(哪个更小),以便在您键入时自动更改大小以适应内容。

      【讨论】:

      • 你有这个样本吗?
      【解决方案5】:

      似乎很令人沮丧,以至于在 IB 本身中没有像 UILabel 的“自动缩小”到“最小字体大小”这样的直接方法。 IB 中文本字段的“调整以适应”也不好。

      为什么 Apple 让我们编写所有这些样板代码,而文本字段需要 Autoshrink 的程度不亚于 UILabel!

      【讨论】:

        【解决方案6】:

        您可以通过覆盖UITextField 类并在intrinsicContentSize 中返回自定义值来实现它。您还需要订阅文本更改事件并使文本更改动画的内在内容大小无效

        这是 Swift 3 中的示例

        class Test: UITextField {
        
            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: nil) { (notification) in
                        UIView.animate(withDuration: 0.05, animations: {
                            self.invalidateIntrinsicContentSize()
                        })
                }
            }
        
            deinit {
                NotificationCenter.default.removeObserver(self)
            }
        
            override var intrinsicContentSize: CGSize {
                if isEditing {
                    if let text = text,
                        !text.isEmpty {
                        // Convert to NSString to use size(attributes:)
                        let string = text as NSString
                        // Calculate size for current text
                        var size = string.size(attributes: typingAttributes)
                        // Add margin to calculated size
                        size.width += 10
                        return size
                    } else {
                        // You can return some custom size in case of empty string
                        return super.intrinsicContentSize
                    }
                } else {
                    return super.intrinsicContentSize
                }
            }
        }
        

        【讨论】:

          【解决方案7】:

          获取特定字符串宽度的一种厚颜无耻的解决方法是

          func getWidth(text: String) -> CGFloat {
              let txtField = UITextField(frame: .zero)
              txtField.text = text
              txtField.sizeToFit()
              return txtField.frame.size.width
          }
          

          为了得到宽度,

          let width = getWidth(text: "Hello world")
          txtField.frame.size.width = width
          self.view.layoutIfNeeded() // if you use Auto layout
          

          如果你有一个与 txtField 的宽度相关的约束,那么做

          yourTxtFieldWidthConstraint.constant = width
          self.view.layoutIfNeeded() // if you use Auto layout
          

          编辑 我们正在创建一个框架基本上全为零的 UITextField。当您调用 sizeToFit() 时,它会设置 UITextField 的框架,使其显示其所有内容,周围几乎没有多余的空格。我们只想要它的宽度,所以我返回了新创建的 UITextField 的宽度。 ARC 会帮我们把它从内存中删除。

          更新

          func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
          
                  if textField.text != nil {
                      let text = textField.text! as NSString
                      let finalString = text.replacingCharacters(in: range, with: string)
                      textField.frame.size.width = getWidth(text: finalString)
                  }
          
                  return true
              }
          

          【讨论】:

          • 我写了这个函数,但不明白,在哪里写 yourTxtFieldWidthConstraint.constant = width self.layoutIfNeeded() // 如果你使用自动布局
          • 这是你的宽度限制的出口。在“shouldChangeCharacterInRange”文本字段委托中执行此操作
          • 但我在 textfield 中写入任何文本,自动增加
          • 如果你在你的控制器里做,它应该是self.view.layoutIfNeeded()
          • 当我删除该文本时,文本字段大小不会改变。宽度计数不正确
          【解决方案8】:

          实现UITextFieldDelegate的以下方法。使用 Matt 提供的方法来获取所需的 textField 宽度。在自动布局中,确保您为文本字段设置了中心和宽度约束。在代码文件中为您的宽度约束创建 IBOutlet。还要确保设置 textField 的委托属性

          @IBOutlet weak var widthConstraint: NSLayoutConstraint!
          
          func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
               let width = getWidth(text : textField.text)
               if width > widthConstraint.constant {
                   widthConstraint.constant = width
               }
               self.layoutIfNeeded() 
               return true
          }
          

          【讨论】:

          • 在这种情况下执行 self.view.layoutIfNeeded()
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-11-16
          • 2018-11-07
          • 2023-04-06
          • 2014-07-07
          • 2016-09-28
          • 2015-04-29
          相关资源
          最近更新 更多