【问题标题】:How do I size a UITextView to its content?如何根据内容调整 UITextView 的大小?
【发布时间】:2010-09-08 04:56:30
【问题描述】:

有没有调整UITextView 的大小以符合其内容的好方法?比如说我有一个包含一行文本的UITextView

"Hello world"

然后我添加另一行文本:

"Goodbye world"

在 Cocoa Touch 中是否有一个很好的方法来获取 rect,它将保存文本视图中的所有行,以便我可以相应地调整父视图?

作为另一个示例,查看日历应用程序中事件的注释字段 - 请注意单元格(以及它包含的 UITextView)如何扩展以容纳注释字符串中的所有文本行。

【问题讨论】:

  • 请考虑更新正确答案,因为接受的答案会导致不必要的计算,现在有一个 contentSize 属性来解决这个问题。
  • 为什么没有关于如何以非动态方式执行此操作的问题?我什至不知道如何静态地做到这一点。并且提供的解决方案似乎没有覆盖情节提要中的“约束”。

标签: ios cocoa-touch autolayout uikit uitextview


【解决方案1】:

迅速回答: 以下代码计算 textView 的高度。

                let maximumLabelSize = CGSize(width: Double(textView.frame.size.width-100.0), height: DBL_MAX)
                let options = NSStringDrawingOptions.TruncatesLastVisibleLine | NSStringDrawingOptions.UsesLineFragmentOrigin
                let attribute = [NSFontAttributeName: textView.font!]
                let str = NSString(string: message)
                let labelBounds = str.boundingRectWithSize(maximumLabelSize,
                    options: NSStringDrawingOptions.UsesLineFragmentOrigin,
                    attributes: attribute,
                    context: nil)
                let myTextHeight = CGFloat(ceilf(Float(labelBounds.height)))

现在您可以将 textView 的高度设置为 myTextHeight

【讨论】:

  • 对不起,这是什么意思:let attribute = [NSFontAttributeName: textView.text.font!] 这真的是没有错误的 Swift 代码吗?)你的意思是 let attribute = [NSFontAttributeName: textView.font!]
【解决方案2】:

如果您需要在staticTableView 中动态调整textViewtableViewCell 的大小,这就是答案

[https://stackoverflow.com/a/43137182/5360675][1]

【讨论】:

    【解决方案3】:

    在 ios 11 上像魅力一样工作 我在一个单元格中工作,就像一个带有气泡的聊天单元格。

    let content = UITextView(frame: CGRect(x: 4, y: 4, width: 0, height: 0))
    content.text = "what ever short or long text you wanna try"
    content.textAlignment = NSTextAlignment.left
    content.font = UIFont.systemFont(ofSize: 13)
    let spaceAvailable = 200 //My cell is fancy I have to calculate it...
    let newSize = content.sizeThatFits(CGSize(width: CGFloat(spaceAvailable), height: CGFloat.greatestFiniteMagnitude))
    content.isEditable = false
    content.dataDetectorTypes = UIDataDetectorTypes.all
    content.isScrollEnabled = false
    content.backgroundColor = UIColor.clear
    bkgView.addSubview(content)
    

    【讨论】:

    • 注意:所以这个答案只是为了强调如果你限制到某个宽度或高度,你不必使用 CGFloat.greatestFiniteMagnitude -> 在我的情况下,spaceAvailable 可以是最大的屏幕宽度 - 间距和其他标签宽度或最小屏幕宽度都取决于我显示的内容...
    【解决方案4】:

    此方法似乎适用于 ios7

     // Code from apple developer forum - @Steve Krulewitz, @Mark Marszal, @Eric Silverberg
    - (CGFloat)measureHeight
    {
        if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)])
        {
        CGRect frame = internalTextView.bounds;
        CGSize fudgeFactor;
        // The padding added around the text on iOS6 and iOS7 is different.
        fudgeFactor = CGSizeMake(10.0, 16.0);
    
        frame.size.height -= fudgeFactor.height;
        frame.size.width -= fudgeFactor.width;
    
        NSMutableAttributedString* textToMeasure;
        if(internalTextView.attributedText && internalTextView.attributedText.length > 0){
            textToMeasure = [[NSMutableAttributedString alloc] initWithAttributedString:internalTextView.attributedText];
        }
        else{
            textToMeasure = [[NSMutableAttributedString alloc] initWithString:internalTextView.text];
            [textToMeasure addAttribute:NSFontAttributeName value:internalTextView.font range:NSMakeRange(0, textToMeasure.length)];
        }
    
        if ([textToMeasure.string hasSuffix:@"\n"])
        {
            [textToMeasure appendAttributedString:[[NSAttributedString alloc] initWithString:@"-" attributes:@{NSFontAttributeName: internalTextView.font}]];
        }
    
        // NSAttributedString class method: boundingRectWithSize:options:context is
        // available only on ios7.0 sdk.
        CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT)
                                                  options:NSStringDrawingUsesLineFragmentOrigin
                                                  context:nil];
    
        return CGRectGetHeight(size) + fudgeFactor.height;
    }
    else
    {
        return self.internalTextView.contentSize.height;
    }
    }
    

    【讨论】:

      【解决方案5】:

      询问UITextView 的最简单方法是调用-sizeToFit,它应该也适用于scrollingEnabled = YES,然后检查高度并在文本视图上添加具有相同值的高度约束。
      注意UITexView 包含插入,这意味着您不能询问字符串对象要使用多少空间,因为这只是文本的边界矩形。
      所有使用-sizeToFit 遇到错误大小的人可能是由于文本视图尚未布局到界面大小。
      当您使用大小类和 UITableView 时,总是会发生这种情况,第一次在 - tableView:cellForRowAtIndexPath: 中创建单元格时,会出现任意配置的大小,如果您计算您刚才的值,则文本视图将具有与预期不同的宽度,这将拧紧所有尺寸。
      为了克服这个问题,我发现重写单元格的 -layoutSubviews 方法以重新计算 textview 高度很有用。

      【讨论】:

        【解决方案6】:

        如果您使用滚动视图和内容视图,并且您想根据 TextView 内容高度增加高度,那么这段代码将帮助您。

        希望这会有所帮助,它在 iOS9.2 中完美运行

        当然还有textview.scrollEnabled = NO;

        -(void)adjustHeightOfTextView
        {
            //this pieces of code will helps to adjust the height of the uitextview View W.R.T content
            //This block of code work will calculate the height of the textview text content height and calculate the height for the whole content of the view to be displayed.Height --> 400 is fixed,it will change if you change anything in the storybord.
        
        
        CGSize textViewSize = [self.textview sizeThatFits:CGSizeMake(self.view.frame.size.width, self.view.frame.size.height)];//calulcate the content width and height
        
        float textviewContentheight =textViewSize.height;
        self.scrollview.contentSize = CGSizeMake(self.textview.frame.size.width,textviewContentheight + 400);//height value is passed
        self.scrollview.frame =CGRectMake(self.scrollview.frame.origin.x, self.scrollview.frame.origin.y, self.scrollview.frame.size.width, textviewContentheight+400);
        
        CGRect Frame = self.contentview.frame;
        Frame.size.height = textviewContentheight + 400;
        [self.contentview setFrame:Frame];
        
        self.textview.frame =CGRectMake(self.textview.frame.origin.x, self.textview.frame.origin.y, self.textview.frame.size.width, textviewContentheight);
        [ self.textview setContentSize:CGSizeMake( self.textview.frame.size.width,textviewContentheight)];
        self.contenview_heightConstraint.constant = 
        
        self.scrollview.bounds.size.height;
            NSLog(@"%f",self.contenview_heightConstraint.constant);
        }
        

        【讨论】:

          【解决方案7】:

          使用 Key Value Observing (KVO) 非常简单,只需创建 UITextView 的子类并执行以下操作:

          private func setup() { // Called from init or somewhere
          
              fitToContentObservations = [
                  textView.observe(\.contentSize) { _, _ in
                      self.invalidateIntrinsicContentSize()
                  },
                  // For some reason the content offset sometimes is non zero even though the frame is the same size as the content size.
                  textView.observe(\.contentOffset) { _, _ in
                      if self.contentOffset != .zero { // Need to check this to stop infinite loop
                          self.contentOffset = .zero
                      }
                  }
              ]
          }
          public override var intrinsicContentSize: CGSize {
              return contentSize
          }
          

          如果您不想子类化,可以尝试在 contentSize 观察者中执行 textView.bounds = textView.contentSize

          【讨论】:

            【解决方案8】:

            对我有用的最简单的解决方案是在 Storyboard 中的 textView 上设置高度约束,然后将 textView 和高度约束连接到代码:

            @IBOutlet var myAwesomeTextView: UITextView!
            @IBOutlet var myAwesomeTextViewHeight: NSLayoutConstraint!
            

            然后在设置好文字和段落样式后,在viewDidAppear中添加这个:

            self.myAwesomeTextViewHeight.constant = self.myAwesomeTextView.contentSize.height
            

            一些注意事项:

            1. 与其他解决方案相比,isScrollEnabled 必须设置为 true 才能正常工作。
            2. 就我而言,我在代码中为字体设置了自定义属性,因此我必须在 viewDidAppear 中设置高度(在此之前它无法正常工作)。如果您没有在代码中更改任何文本属性,您应该能够在 viewDidLoad 或设置文本后的任何位置设置高度。

            【讨论】:

              【解决方案9】:

              看起来这家伙为 NSTextView 想出来了,他的回答也适用于 iOS。结果intrinsicContentSize 没有与布局管理器同步。如果在intrinsicContentSize 之后发生布局,您可能会有差异。

              他有一个简单的解决办法。

              NSTextView in NSOutlineView with IntrinsicContentSize setting wrong height

              【讨论】:

                【解决方案10】:

                步骤如下

                解决方案适用于所有版本的 iOS。斯威夫特 3.0 及更高版本。

                1. 将您的UITextView 添加到View。我是用代码添加的,你可以通过界面生成器添加。
                2. 添加约束。我在代码中添加约束,你也可以在界面生成器中添加。
                3. 使用UITextViewDelegate方法func textViewDidChange(_ textView: UITextView)调整TextView的大小

                代码:

                1. //1. Add your UITextView in ViewDidLoad
                  let textView = UITextView()
                  textView.frame = CGRect(x: 0, y: 0, width: 200, height: 100)
                  textView.backgroundColor = .lightGray
                  textView.text = "Here is some default text."
                  
                  
                  
                  //2. Add constraints
                  textView.translatesAutoresizingMaskIntoConstraints = false
                  [
                  textView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
                  textView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
                  textView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
                  textView.heightAnchor.constraint(equalToConstant: 50),
                  textView.widthAnchor.constraint(equalToConstant: 30)
                  ].forEach{ $0.isActive = true }
                  
                  textView.font = UIFont.preferredFont(forTextStyle: .headline)
                  
                  textView.delegate = self
                  textView.isScrollEnabled = false
                  
                  textViewDidChange(textView)
                  
                  
                  //3. Implement the delegate method.
                  func textViewDidChange(_ textView: UITextView) {
                  let size = CGSize(width: view.frame.width, height: .infinity)
                  let estimatedSize = textView.sizeThatFits(size)
                  
                  textView.constraints.forEach { (constraint) in
                      if constraint.firstAttribute == .height {
                          print("Height: ", estimatedSize.height)
                          constraint.constant = estimatedSize.height
                      }
                  }
                  }
                  

                【讨论】:

                  【解决方案11】:

                  不知道为什么人们总是把事情复杂化: 在这里:

                  - (void)textViewDidChange:(UITextView *)textView{ CGRect frame = textView.frame;
                  CGFloat height = [self measureHeightOfUITextView:textView];
                  CGFloat insets = textView.textContainerInset.top + textView.textContainerInset.bottom;
                  height += insets;
                  frame.size.height = height;
                  
                  if(frame.size.height > textView.frame.size.height){
                      CGFloat diff = frame.size.height - textView.frame.size.height;
                      textView.frame = CGRectMake(5, textView.frame.origin.y - diff, textView.frame.size.width, frame.size.height);
                  }
                  else if(frame.size.height < textView.frame.size.height){
                      CGFloat diff = textView.frame.size.height - frame.size.height;
                      textView.frame = CGRectMake(5, textView.frame.origin.y + diff, textView.frame.size.width, frame.size.height);
                  }
                  [textView setNeedsDisplay];
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-03-30
                    • 2013-11-19
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-10-03
                    • 1970-01-01
                    相关资源
                    最近更新 更多