【问题标题】:Resize font size to fill UITextView?调整字体大小以填充 UITextView?
【发布时间】:2011-01-03 13:59:40
【问题描述】:

如何在 UITextView 中设置文本的字体大小以使其填充整个 UITextView?我希望用户输入他们的文本,然后让文本填充整个 UITextView。

感谢任何帮助!

【问题讨论】:

    标签: iphone cocoa-touch uikit uitextview font-size


    【解决方案1】:

    此属性仅在 UITextFields 上可用。要在 UITextView 中执行此操作,您必须不断观察文本并在更改时手动调整字体大小。

    【讨论】:

    • 啊,有没有示例代码可以做到这一点?我环顾四周,找不到任何东西。非常感谢!
    • 我不知道任何示例代码;我以前从未听说过有人尝试这样做。
    【解决方案2】:

    这在 UITextView 的一个类别中应该可以解决问题。为什么需要 fudgefactor,请参阅 this post

    #define kMaxFieldHeight 9999 
    
    -(BOOL)sizeFontToFit:(NSString*)aString minSize:(float)aMinFontSize maxSize:(float)aMaxFontSize 
    {   
    float fudgeFactor = 16.0;
    float fontSize = aMaxFontSize;
    
    self.font = [self.font fontWithSize:fontSize];
    
    CGSize tallerSize = CGSizeMake(self.frame.size.width-fudgeFactor,kMaxFieldHeight);
    CGSize stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
    
    while (stringSize.height >= self.frame.size.height)
           {
           if (fontSize <= aMinFontSize) // it just won't fit
               return NO;
    
           fontSize -= 1.0;
           self.font = [self.font fontWithSize:fontSize];
           tallerSize = CGSizeMake(self.frame.size.width-fudgeFactor,kMaxFieldHeight);
           stringSize = [aString sizeWithFont:self.font constrainedToSize:tallerSize lineBreakMode:UILineBreakModeWordWrap];
           }
    
    return YES; 
    }
    

    【讨论】:

    • 在 iOS >7.0 中你需要将 UILineBreakModeWordWrap 更改为 NSLineBreakByWordWrapping
    • 只是好奇,你怎么知道“fudgeFactor = 16.0”?我相信当文本大小更小时这个值应该更小
    【解决方案3】:

    试试这个,简单多了:

    while (self.contentSize.height > self.frame.size.height)
    {
        self.font = [self.font fontWithSize:self.font.pointSize -1];
        [self layoutSubviews];//force .contentSize to update
    }
    

    【讨论】:

    • @BradMoore,你需要多加一行:[textView layoutSubviews];
    • @Jacky,很高兴知道!如果我重新访问这段代码,我会看看它是否值得更新。
    • @Jacky - 你想调用的实际上是 [textView layoutIfNeeded]
    • @BradMoore 这应该是最佳答案。我还注意到这个问题在 2012 年得到了回答,现在分辨率太高了,应该考虑小数字体大小。我使用 -0.5 而不是 -1,它在所有设备尺寸上都非常顺利。
    【解决方案4】:

    与 Arie Litovsky 的答案类似,但没有子分类(或使用类别),也没有使用 contentSize,它没有为我返回渲染文本的正确高度。在 iOS 7 上测试:

    while (((CGSize) [_textView sizeThatFits:_textView.frame.size]).height > _textView.frame.size.height) {
        _textView.font = [_textView.font fontWithSize:_textView.font.pointSize-1];
    }
    

    方法是不断减小字体大小,直到文本刚好适合文本视图的框架。

    如果您要在生产中使用它,您仍然需要:

    • 处理即使使用尽可能小的字体大小仍无法容纳文本的情况。
    • 如果您还想向上缩放文本以适合框架,请使用类似的方法增加字体大小。

    【讨论】:

      【解决方案5】:

      这是我的示例代码。基本上,我检查期望大小以了解字体大小是否需要增加或减少。您需要将 UITextViewDelegate 添加到您的课程中以确保其正常工作

      - (void)updateTextFont:(UITextView *)textView
      {
          // Only run if has text, otherwise it will make infinity loop
          if (textView.text.length == 0 || CGSizeEqualToSize(textView.bounds.size, CGSizeZero)) return;
      
          /*
           - Update textView font size
           If expectHeight > textViewHeight => descrease font size n point until it reach textViewHeight
           If expectHeight < textViewHeight => inscrease font size n point until it reach textViewHeight
           */
          CGSize textViewSize = textView.frame.size;
          CGFloat fixedWidth = textViewSize.width;
          CGSize expectSize = [textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)];
      
          UIFont *expectFont = textView.font;
          if (expectSize.height > textViewSize.height) {
              while ([textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)].height > textViewSize.height) {
                  expectFont = [textView.font fontWithSize:(textView.font.pointSize-1)];
                  textView.font = expectFont;
              }
          } else {
              while ([textView sizeThatFits:CGSizeMake(fixedWidth, MAXFLOAT)].height < textViewSize.height) {
                  expectFont = textView.font;
                  textView.font = [textView.font fontWithSize:(textView.font.pointSize+1)];
              }
              textView.font = expectFont;
          }
      }
      

      【讨论】:

      • 我很好奇 else 子句在这里做了什么。在修改之前将expectFont 设置为textView's font... 然后将其设置回未修改的font?是为了防止文字大小的上下跳跃吗?
      • @StephenPaul 在 else 子句中,如果 while 没有运行,textView.font 不会改变(因为expectFont 实际上是原始的textView.font)。但是如果至少运行 1 次,expectFont 会发生变化,我们需要在完成循环后更新它。我可以制作一个标志来确定是否运行,但我没有。相反,我将它分组到最后一行 textView.font = expectFont
      • 如果 while 循环至少运行 1 次,则将当前字体存储在变量 expectFont 中。然后你将textView 的字体增加一点,但是当while 循环退出时,你会看到textView 字体恢复到原来的样子......
      • 你设置*,我的意思是。
      • 是的,因为上次设置了textView.font,所以while条件为false(我是直接用textView计算条件的)。这意味着我设置的字体不正确,我必须回滚才能期待字体。
      【解决方案6】:

      我已将dementiazz's answer 转换为 Swift:

      func updateTextFont() {
          if (textView.text.isEmpty || CGSizeEqualToSize(textView.bounds.size, CGSizeZero)) {
              return;
          }
      
          let textViewSize = textView.frame.size;
          let fixedWidth = textViewSize.width;
          let expectSize = textView.sizeThatFits(CGSizeMake(fixedWidth, CGFloat(MAXFLOAT)));
      
          var expectFont = textView.font;
          if (expectSize.height > textViewSize.height) {
              while (textView.sizeThatFits(CGSizeMake(fixedWidth, CGFloat(MAXFLOAT))).height > textViewSize.height) {
                  expectFont = textView.font!.fontWithSize(textView.font!.pointSize - 1)
                  textView.font = expectFont
              }
          }
          else {
              while (textView.sizeThatFits(CGSizeMake(fixedWidth, CGFloat(MAXFLOAT))).height < textViewSize.height) {
                  expectFont = textView.font;
                  textView.font = textView.font!.fontWithSize(textView.font!.pointSize + 1)
              }
              textView.font = expectFont;
          }
      }
      

      Swift 3.0+ 更新:

      func updateTextFont() {
          if (textView.text.isEmpty || textView.bounds.size.equalTo(CGSize.zero)) {
              return;
          }
      
          let textViewSize = textView.frame.size;
          let fixedWidth = textViewSize.width;
          let expectSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)));
      
          var expectFont = textView.font;
          if (expectSize.height > textViewSize.height) {
              while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
                  expectFont = textView.font!.withSize(textView.font!.pointSize - 1)
                  textView.font = expectFont
              }
          }
          else {
              while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
                  expectFont = textView.font;
                  textView.font = textView.font!.withSize(textView.font!.pointSize + 1)
              }
              textView.font = expectFont;
          }
      }
      

      【讨论】:

      • 您还可以添加最小和最大字体大小以避免意外大小。 (太大或太小)我刚刚将条件“&& (textView.font!.pointSize > CGFloat(minSize))”添加到您的 while
      • @RubenVot,我们什么时候应该使用这个功能?
      • 不适合我。有什么需要注意的吗?
      • 重要的是在正确的时刻运行它。在 UITextView 获得正确的框架之后。在我的情况下viewDidLayoutSubviews
      • 这不处理行孤字母,有谁知道我该怎么做?
      【解决方案7】:

      @Arie Litovsky 代码的更新版本。这适用于 iOS7 及更高版本,并且可以上下拉伸字体大小以使文本适合。

      - (void) stretchFontToFit:(UITextView*)textView
      {
      
          while( textView.contentSize.height < textView.frame.size.height )
          {
              textView.font = [textView.font fontWithSize:textView.font.pointSize +1];
              [textView layoutIfNeeded];
          }
      
          while( textView.contentSize.height > textView.frame.size.height )
          {
              textView.font = [textView.font fontWithSize:textView.font.pointSize -1];
              [textView layoutIfNeeded];
          }
      }
      

      【讨论】:

        【解决方案8】:

        在 viewDidLoad 中:

        textView.textContainer.lineFragmentPadding = 0;
        textView.textContainerInset = UIEdgeInsetsMake(0, 0, 0, 0);
        

        需要添加 UITextViewDelegate:

        - (void)updateTextFont:(UITextView *)textView {
        
            CGSize textViewSize = textView.frame.size;
            CGSize sizeOfText = [textView.text sizeWithAttributes:@{NSFontAttributeName: textView.font}];
        
            CGFloat fontOfWidth = floorf(textView.font.pointSize / sizeOfText.height * textViewSize.height);
            CGFloat fontOfHeight = floorf(textView.font.pointSize / sizeOfText.width * textViewSize.width);
        
            textView.font = [textView.font fontWithSize:MIN(fontOfHeight, fontOfWidth)];
        }
        

        【讨论】:

          【解决方案9】:

          我已将痴呆症和马特弗雷尔的答案转换为 Swift 3:

          func updateTextFont() {
                  if (textView.text.isEmpty || textView.bounds.size.equalTo(CGSize.zero)) {
                      return
                  }
          
              let textViewSize = textView.frame.size
              let fixedWidth = textViewSize.width
              let expectSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))
          
              var expectFont = textView.font
              if (expectSize.height > textViewSize.height) {
                  while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
                      expectFont = textView.font!.withSize(textView.font!.pointSize - 1)
                      textView.font = expectFont
                  }
              }
              else {
                  while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
                      expectFont = textView.font
                      textView.font = textView.font!.withSize(textView.font!.pointSize + 1)
                  }
                  textView.font = expectFont
              }
          }
          

          【讨论】:

            【解决方案10】:

            你可以通过使用轻松做到这一点

            • self.textview.font =

            self.textview.font = UIFont(name: self.textview.font!.fontName,
            尺寸:self.textview.frame.size.height / 10)!

            根据您的要求将 textview.frame.size.height 划分为某个常数..

            【讨论】:

              【解决方案11】:

              对于 Swift 3

                  func updateTextFont(textView: UITextView) {
                   if (textView.text.isEmpty || textView.bounds.size.equalTo(CGSize.zero)) {
                      return
                   }
                   let textViewSize = textView.frame.size
                   let fixedWidth = textViewSize.width
                   let expectSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))
                   var expectFont = textView.font;
                   if (expectSize.height > textViewSize.height) {
                      while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
                          expectFont = textView.font!.withSize(textView.font!.pointSize - 1)
                          textView.font = expectFont
                      }
                   }
                   else {
                      while (textView.sizeThatFits(CGSize(width: fixedWidth,height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
                          expectFont = textView.font
                          textView.font = textView.font!.withSize(textView.font!.pointSize + 1)
                      }
                      textView.font = expectFont
                   }
               }
              

              【讨论】:

                【解决方案12】:

                这是 Swift 4 的解决方案(基于Arie Litovsky 答案),您可以将此代码放入textViewDidChange(_ textView: UITextView) 委托方法中:

                缩小字体:

                    while (textView.contentSize.height > textView.frame.size.height) {
                        guard let fontName = textView.font?.fontName, let fontSize = textView.font?.pointSize else {return}
                        if fontSize < 12 {
                            return
                        }
                        textView.font = UIFont(name: fontName, size: fontSize - 1)
                        textView.layoutIfNeeded()
                    }
                

                并放大字体:

                        while (textView.contentSize.height < textView.frame.size.height) {
                        guard let fontName = textView.font?.fontName, let fontSize = textView.font?.pointSize else {return}
                        if fontSize > 15 {
                            return
                        }
                        textView.font = UIFont(name: fontName, size: fontSize + 1)
                        textView.layoutIfNeeded()
                    }
                

                您可以更改fontSize &lt; 12fontSize &gt; 15 以满足您对最小和最大字体大小的需求。

                【讨论】:

                  【解决方案13】:

                  我已将 Matt Frear 的答案转换为 Swift 4.1 作为 UITextView 的扩展:

                  extension UITextView {
                  func updateTextFont() {
                      if (self.text.isEmpty || self.bounds.size.equalTo(CGSize.zero)) {
                          return;
                      }
                  
                      let textViewSize = self.frame.size;
                      let fixedWidth = textViewSize.width;
                      let expectSize = self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))
                  
                  
                      var expectFont = self.font
                      if (expectSize.height > textViewSize.height) {
                  
                          while (self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
                              expectFont = self.font!.withSize(self.font!.pointSize - 1)
                              self.font = expectFont
                          }
                      }
                      else {
                          while (self.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
                              expectFont = self.font
                              self.font = self.font!.withSize(self.font!.pointSize + 1)
                          }
                          self.font = expectFont
                      }
                  }
                  }
                  

                  【讨论】:

                    【解决方案14】:

                    这里是dementiazz'sMatt Frear's 对Swift 5 的回答的转换。将此函数放入viewDidLayoutSubviews,引用UITextView 的要动态调整大小的字体。

                    func updateTextFont(textView: UITextView) {
                        if (textView.text.isEmpty || textView.bounds.size.equalTo(CGSize.zero)) {
                            return;
                        }
                    
                        let textViewSize = textView.frame.size;
                        let fixedWidth = textViewSize.width;
                        let expectSize = textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT)))
                    
                        var expectFont = textView.font;
                        if (expectSize.height > textViewSize.height) {
                            while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height > textViewSize.height) {
                                expectFont = textView.font!.withSize(textView.font!.pointSize - 1)
                                textView.font = expectFont
                            }
                        }
                        else {
                            while (textView.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat(MAXFLOAT))).height < textViewSize.height) {
                                expectFont = textView.font;
                                textView.font = textView.font!.withSize(textView.font!.pointSize + 1)
                            }
                            textView.font = expectFont;
                        }
                    }
                    

                    【讨论】:

                      【解决方案15】:

                      希望这更清楚:

                      extension UITextView {
                          @objc public func fitText() {
                              fitText(into: frame.size)
                          }
                      
                          @objc public func fitText(into originalSize: CGSize) {
                              let originalWidth = originalSize.width
                              let expectedSize = sizeThatFits(CGSize(width: originalWidth, height: CGFloat(MAXFLOAT)))
                      
                              if expectedSize.height > originalSize.height {
                                  while let font = self.font, sizeThatFits(CGSize(width: originalWidth, height: CGFloat(MAXFLOAT))).height > originalSize.height {
                                      self.font = font.withSize(font.pointSize - 1)
                                  }
                              } else {
                                  var previousFont = self.font
                                  while let font = self.font, sizeThatFits(CGSize(width: originalWidth, height: CGFloat(MAXFLOAT))).height < originalSize.height {
                                      previousFont = font
                                      self.font = font.withSize(font.pointSize + 1)
                                  }
                                  self.font = previousFont
                              }
                          }
                      }
                      

                      【讨论】:

                        猜你喜欢
                        • 2016-02-26
                        • 2013-11-25
                        • 1970-01-01
                        • 2015-04-05
                        • 1970-01-01
                        • 1970-01-01
                        • 2022-01-09
                        • 2011-12-11
                        • 2016-12-12
                        相关资源
                        最近更新 更多