【问题标题】:How do I sizeToFit a UILabel by changing only the height and not the width?如何通过仅更改高度而不更改宽度来调整 UILabel 的大小?
【发布时间】:2012-10-15 14:13:07
【问题描述】:
[self.Review sizeToFit];

sizeToFit 之前的结果:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {198, 63}}

sizeToFit 后的结果:

NSStringFromCGRect(self.Review.frame): {{90, 20}, {181, 45}}

我希望宽度保持不变。我只是想改变高度。自动掩码是

(lldb) po self.Review
(UILabel *) $1 = 0x08bb0fe0 <UILabel: 0x8bb0fe0; frame = (90 20; 181 45); text = 'I'm at Mal Taman Anggrek ...'; clipsToBounds = YES; opaque = NO; autoresize = LM+RM+H; userInteractionEnabled = NO; layer = <CALayer: 0x8bb68b0>>

我知道有一种方法可以做到这一点: How to adjust and make the width of a UILabel to fit the text size?

答案要么很奇怪(我们需要重新提供字体信息)。或者不清楚。

您还需要定义最大宽度,并告诉您的程序 如果 sizeToFit 为您提供的宽度大于该最大值,该怎么办。

我将使用sizeWithFont这个奇怪的解决方案。很奇怪,因为 UILabel 已经知道标签中的字体了。

实际上 sizeToFit 的行为如何?它如何决定我们需要更薄还是更高的 UILabel?

【问题讨论】:

  • sizeWithFont 是 NSString 的方法,而不是 UILable 的方法

标签: objective-c uilabel xcode4.5


【解决方案1】:

您可以使用 sizeThatFits 获得相同的结果。

CGSize size = [label sizeThatFits:CGSizeMake(label.frame.size.width, CGFLOAT_MAX)];
CGRect frame = label.frame;
frame.size.height = size.height;
label.frame = frame;

或者,使用 sizeToFit。

CGRect frame = label.frame;
[label sizeToFit];
frame.size.height = label.frame.size.height;
label.frame = frame;

【讨论】:

  • 已停止使用您的解决方案!但只有一个更正......他想保留 HEIGTH,而在您的第二个选项(我使用的那个)中,您将保留 WIDTH。
  • 使用 iOS 7(或 8)时,这是最好的工作答案,因为 sizeWithFont: 在 iOS 7 及更高版本中已弃用
【解决方案2】:

这就是它的完成方式。因为标签已经包含了字体信息,所以在这个方法调用中包含它是微不足道的。

CGSize size = [label.text sizeWithFont:label.font
                     constrainedToSize:CGSizeMake(maxWidth, MAXFLOAT)
                         lineBreakMode:UILineBreakModeWordWrap]; 
CGRect labelFrame = label.frame;
labelFrame.size.height = size.height;
label.frame = labelFrame;

Swift 版本使用更新的boundingRectWithSize

let maxHeight = CGFloat.infinity
let rect = label.attributedText?.boundingRectWithSize(CGSizeMake(maxWidth, maxHeight), 
       options: .UsesLineFragmentOrigin, context: nil)
var frame = label.frame
frame.size.height = rect.size.height
label.frame = frame

【讨论】:

  • 和 maxWidth 将只是 label.frame.size.width?
  • 对。我认为您可能还想在其他地方指定它。但如果标签已经有正确的大小,label.frame.size.width 将保持原样。
  • 我最初使用sizeToFit,但发现有时当文本可以放在一行中时,它会无缘无故地将其分成两部分。这种方法不会导致这个问题
  • sizetofit 有时它不会更新,但这个确实有效!
  • sizeWithFont 已经被弃用了一段时间。参见 UILabel 的 sizeThatFits 和 NSString 的 boundingRectWithSize
【解决方案3】:

sizeToFit 效果很好。唯一的问题是它基于控件的当前大小。

例如,如果您正在回收带有标签的表格视图单元格,则标签的宽度可能已在前一个单元格中减小,因此对 sizeToFit 的调用可能看起来不可靠。

只需在发送 sizeToFit 消息之前重置控件的原始宽度即可。

【讨论】:

  • 这是被低估的无价信息
  • @ChuckKelly,我完全同意。
  • 非常感谢,这让一切变得如此简单!
  • 正是我的问题。但是如何重置为原始宽度?它由前导/尾随约束设置。
  • 在这种情况下,您不必调整控件的大小。还是高度的问题?
【解决方案4】:

针对 Swift 3 的这个问题的简单扩展。

extension UILabel {
    func sizeToFitHeight() {
        let size: CGSize = self.sizeThatFits(CGSize.init(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude))
        var frame:CGRect = self.frame
        frame.size.height = size.height
        self.frame = frame
    }
}

【讨论】:

    【解决方案5】:

    我认为你不应该使用NSStringsize... 方法,UILabel 已经有一个 API,正如@vatrif 指出的那样(内部可能只使用NSString 的方法)。

    不过我认为UILabel 的API 可以改进。这就是为什么我认为类别是最优雅的解决方案:

    //  UILabel+Resize.h
    @interface UILabel (Resize)
    - (void)sizeToFitHeight;
    @end
    
    //  UILabel+Resize.m
    @implementation UILabel (Resize)
    - (void)sizeToFitHeight {
        CGSize size = [self sizeThatFits:CGSizeMake(self.frame.size.width, CGFLOAT_MAX)];
        CGRect frame = self.frame;
        frame.size.height = size.height;
        self.frame = frame;
    }
    @end
    

    只有一件事:我不确定该方法的适当名称:

    • sizeToFitHeight?
    • heightToFit ?

    非常感谢您的评论,谢谢!

    【讨论】:

      【解决方案6】:

      同意的 API 将从这一添加中受益。让您的生活更轻松,并为 Swift 中的 UILabel 类添加扩展,如下所示:

      extension UILabel {
      
          func sizeToFitHeight() {
              let size:CGSize = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max))
              var frame:CGRect = self.frame
              frame.size.height = size.height
              self.frame = frame
          }
      }
      

      【讨论】:

        【解决方案7】:

        2017 年的答案...

        c = CGSize(宽度: yourWidth, 高度: CGFloat.greatestFiniteMagnitude)
        结果 = sizeThatFits(c).height

        所以...

        let t = .... your UITextView
        let w = .... your known width of the item
        
        let trueHeight = t.sizeThatFits(
                           CGSize(width: t, height: CGFloat.greatestFiniteMagnitude)).height
        

        就是这样。


        您经常想知道与“正常”单行条目相比高度的差异

        如果您正在制作某种与 UTableView 无关的单元格(例如,某种自定义堆栈视图),这尤其会出现。您必须在某些时候手动设置高度。在您的故事板上,按照您的意愿构建它,使用任何短字符串(例如,“A”)的示例文本,在任何正常情况下当然只有一行。然后你做这样的事情......

        func setTextWithSizeCorrection() { // an affaire iOS
        
            let t = .... your UITextView
            let w = .... your known width of the item
        
            let oneLineExample = "A"
            let actualText = yourDataSource[row].description.whatever
            
            // get the height as if with only one line...
            
            experimental.text = oneLineExample
            let oneLineHeight = t.sizeThatFits(
                       CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height
            
            // get the height with the actual long text...
            // (note that usually, you do not want a one-line minimum)
            
            experimental.text = (actualText == "") ? oneLineExample : actualText
            let neededHeight = t.sizeThatFits(
                      CGSize(width: w, height: CGFloat.greatestFiniteMagnitude)).height
            
            experimental.text = actualText
            
            let delta = neededHeight - oneLineHeight
            
            set the height of your cell, or whatever it is(standardHeight + delta)
        }
        

        最后一点:iOS 中真正愚蠢的事情之一是 UITextView 内部有一种奇怪的边距。这意味着您不能只在 UITextViews 和标签之间进行交换;它会导致许多其他问题。截至撰写本文时,Apple 尚未解决此问题。解决这个问题很困难:以下方法通常是可以的:

        @IBDesignable class UITextViewFixed: UITextView {
            override func layoutSubviews() {
                super.layoutSubviews()
                setup()
            }
            func setup() {
                textContainerInset = UIEdgeInsets.zero;
                textContainer.lineFragmentPadding = 0;
            }
        }
        

        来自 Apple 的损坏、无法使用的 UITextView...

        UITextViewFixed 在大多数情况下是可以接受的修复:

        (为清楚起见添加了黄色。)

        【讨论】:

          【解决方案8】:

          SWIFT 3 的固定解决方案

          使用CGFloat.greatestFiniteMagnitude 作为最大高度。

          let size = CGSize.init(width: yourLabel.frame.size.width,
                                 height: CGFloat.greatestFiniteMagnitude)
          let rect = errorLabel.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
          var frame = errorLabel.frame
          frame.size.height = (rect?.size.height)!
          errorLabel.frame = frame
          


          或者创建UIlabel扩展,并调用方法yourLabel. sizeToFitHeight()

          extension UILabel {
          
              func sizeToFitHeight() {
                  let maxHeight : CGFloat = CGFloat.greatestFiniteMagnitude
                  let size = CGSize.init(width: self.frame.size.width, height: maxHeight)
                  let rect = self.attributedText?.boundingRect(with: size, options: .usesLineFragmentOrigin, context: nil)
                  var frame = self.frame
                  frame.size.height = (rect?.size.height)!
                  self.frame = frame
              }
          
          } 
          

          【讨论】:

            【解决方案9】:

            我相信我有一个更简单的解决方案:

            let oldWidth = self.frame.size.width
            label.sizeToFit()
            label.frame.size.width = oldWidth
            

            只需存储旧的宽度,sizeToFit() 适用于宽度和高度,然后将宽度重置回原来的值,只改变标签的高度。

            【讨论】:

              【解决方案10】:

              Swift 3 版本Mundi的回答:

              let maxHeight: CGFloat = 10000
              let rect = label.attributedText!.boundingRect(with: CGSize(width: maxWidth, height: maxHeight),
                                                                         options: .usesLineFragmentOrigin,
                                                                         context: nil)
              var frame = labe.frame
              frame.size.height = rect.size.height
              label.frame = frame
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-12-24
                • 2013-09-11
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-03-16
                相关资源
                最近更新 更多