Swift의 String을 기반으로 UILabel의 크기 파악


183

다른 문자열 길이를 기반으로 UILabel의 높이를 계산하려고합니다.

func calculateContentHeight() -> CGFloat{
    var maxLabelSize: CGSize = CGSizeMake(frame.size.width - 48, CGFloat(9999))
    var contentNSString = contentText as NSString
    var expectedLabelSize = contentNSString.boundingRectWithSize(maxLabelSize, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: UIFont.systemFontOfSize(16.0)], context: nil)
    print("\(expectedLabelSize)")
    return expectedLabelSize.size.height

}

위는 높이를 결정하는 데 사용하는 현재 기능이지만 작동하지 않습니다. 도움을 주시면 감사하겠습니다. Objective C가 아닌 Swift에서 답을 제시합니다.


답변:


518

확장명을 사용하십시오. String

스위프트 3

extension String {
    func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

        return ceil(boundingBox.height)
    }

    func width(withConstrainedHeight height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

        return ceil(boundingBox.width)
    }
}

그리고 또한 NSAttributedString(때때로 매우 유용합니다)

extension NSAttributedString {
    func height(withConstrainedWidth width: CGFloat) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil)

        return ceil(boundingBox.height)
    }

    func width(withConstrainedHeight height: CGFloat) -> CGFloat {
        let constraintRect = CGSize(width: .greatestFiniteMagnitude, height: height)
        let boundingBox = boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, context: nil)

        return ceil(boundingBox.width)
    }
}

스위프트 4

메소드 attributes에서 값을 변경하십시오.extension String

...에서

[NSFontAttributeName: font]

[.font : font]

2
@CodyWeaver widthWithConstrainedHeight 메소드 편집을 확인하십시오.
Kaan Dedeoglu

7
@KaanDedeoglu "numberOfLines"= 0 (UILabel에 따라 다를 수 있음) 또는 lineBreakMode ByWordWrapping을 사용할 때와 같이 동적 높이 문자열에서 어떻게 작동합니까? 내 생각에 이런 속성을 추가하는 것이 [NSFontAttributeName: font, NSLineBreakMode: .ByWordWrapping]었지만 효과가 없었습니다.
Francisc0

1
내 대답을 알아 낸 것 같아 NSParagraphStyleAttributeName : style스타일이 NSMutableParagraphStyle 인 곳에 사용해야합니다 .
Francisc0

4
'boundingRect'대신 'self.boundingRect'를 작성해야합니다. 그렇지 않으면 컴파일 오류가 발생합니다.
Mike M

1
를 사용할 때 내가 발견 한이 답변에 한가지 sizeForItemAtIndexPathA의는 UICollectionView그것의 반환 무시할 것이다insetForSectionAt
잭 샤피로을

15

여러 줄로 된 텍스트의 경우이 답변이 제대로 작동하지 않습니다. UILabel을 사용하여 다른 문자열 확장을 작성할 수 있습니다

extension String {
func height(constraintedWidth width: CGFloat, font: UIFont) -> CGFloat {
    let label =  UILabel(frame: CGRect(x: 0, y: 0, width: width, height: .greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.text = self
    label.font = font
    label.sizeToFit()

    return label.frame.height
 }
}

UILabel은 고정 너비를 가져오고 .numberOfLines는 0으로 설정됩니다. 텍스트를 추가하고 .sizeToFit ()를 호출하면 자동으로 올바른 높이로 조정됩니다.

코드는 Swift 3으로 작성되었습니다.


15
그러나 sizeToFit은 많은 도면 통과로 인해 수백만 개의 성능 문제를 발생시킵니다. 수동으로 크기를 계산하면 자원이 훨씬 저렴합니다.
Marco Pappalardo

2
이 솔루션은 올바른 높이를 보장하기 위해 UILabel의 UIFont를 설정해야합니다.
Matthew Spencer

빈 문자열을 고려하더라도 (답변과 달리) 완벽하게 작동합니다. 자동 높이 셀을 사용하여 tableView의 높이를 계산하는 데 매우 편리합니다!
Hendies

허용 된 답변은 고정 너비가 아닌 고정 된 높이에서 작동한다는 것을 알았습니다. 고정 높이의 경우 텍스트에 줄 바꿈이 없으면 너비를 한 줄에 모두 맞추십시오. 내 대답
MSimic

2
전화 할 필요없이 비슷한 솔루션을 게시했습니다sizeToFit
RyanG

6

여기 나를 위해 일하는 간단한 해결책이 있습니다 ... 다른 다른 게시물과 비슷하지만 전화 할 필요는 포함되어 있지 않습니다. sizeToFit

이것은 Swift 5로 작성되었습니다.

let lbl = UILabel()
lbl.numberOfLines = 0
lbl.font = UIFont.systemFont(ofSize: 12) // make sure you set this correctly 
lbl.text = "My text that may or may not wrap lines..."

let width = 100.0 // the width of the view you are constraint to, keep in mind any applied margins here

let height = lbl.systemLayoutSizeFitting(CGSize(width: width, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel).height

줄 바꿈 등을 처리합니다. 가장 우아한 코드는 아니지만 작업이 완료됩니다.


2
extension String{

    func widthWithConstrainedHeight(_ height: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: height)

        let boundingBox = self.boundingRect(with: constraintRect, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

        return ceil(boundingBox.width)
    }

    func heightWithConstrainedWidth(_ width: CGFloat, font: UIFont) -> CGFloat? {
        let constraintRect = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)

        return ceil(boundingBox.height)
    }

}

1

이것은 Swift 4.1 및 Xcode 9.4.1의 대답입니다.

//This is your label
let proNameLbl = UILabel(frame: CGRect(x: 0, y: 20, width: 300, height: height))
proNameLbl.text = "This is your text"
proNameLbl.font = UIFont.systemFont(ofSize: 17)
proNameLbl.numberOfLines = 0
proNameLbl.lineBreakMode = .byWordWrapping
infoView.addSubview(proNameLbl)

//Function to calculate height for label based on text
func heightForView(text:String, font:UIFont, width:CGFloat) -> CGFloat {
    let label:UILabel = UILabel(frame: CGRect(x: 0, y: 0, width: width, height: CGFloat.greatestFiniteMagnitude))
    label.numberOfLines = 0
    label.lineBreakMode = NSLineBreakMode.byWordWrapping
    label.font = font
    label.text = text

    label.sizeToFit()
    return label.frame.height
}

이제이 함수를 호출합니다

//Call this function
let height = heightForView(text: "This is your text", font: UIFont.systemFont(ofSize: 17), width: 300)
print(height)//Output : 41.0

1

허용 된 답변은 고정 너비가 아니라 고정 된 높이에서 작동한다는 것을 알았습니다. 고정 높이의 경우 텍스트에 줄 바꿈이 없으면 너비를 한 줄에 모두 맞추십시오.

너비 함수는 높이 함수를 여러 번 호출하지만 빠른 계산이며 UITable 행의 함수를 사용하여 성능 문제를 발견하지 못했습니다.

extension String {

    public func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
        let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
        let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [.font : font], context: nil)

        return ceil(boundingBox.height)
    }

    public func width(withConstrainedHeight height: CGFloat, font: UIFont, minimumTextWrapWidth:CGFloat) -> CGFloat {

        var textWidth:CGFloat = minimumTextWrapWidth
        let incrementWidth:CGFloat = minimumTextWrapWidth * 0.1
        var textHeight:CGFloat = self.height(withConstrainedWidth: textWidth, font: font)

        //Increase width by 10% of minimumTextWrapWidth until minimum width found that makes the text fit within the specified height
        while textHeight > height {
            textWidth += incrementWidth
            textHeight = self.height(withConstrainedWidth: textWidth, font: font)
        }
        return ceil(textWidth)
    }
}

1
무엇 minimumTextWrapWidth:CGFloat입니까?
Vyachaslav Gerchicov '20

함수에서 계산을위한 시드 값일뿐입니다. 너비가 클 것으로 예상되는 경우 작은 minimumTextWrapWidth를 선택하면 while 루프가 추가 반복을 거치게됩니다. 따라서 최소 너비가 클수록 좋습니다. 그러나 실제 너비보다 크면 항상 너비가 반환됩니다.
MSimic

0

레이블 텍스트 높이를 확인하고 작업 중입니다.

let labelTextSize = ((labelDescription.text)! as NSString).boundingRect(
                with: CGSize(width: labelDescription.frame.width, height: .greatestFiniteMagnitude),
                options: .usesLineFragmentOrigin,
                attributes: [.font: labelDescription.font],
                context: nil).size
            if labelTextSize.height > labelDescription.bounds.height {
                viewMoreOrLess.hide(byHeight: false)
                viewLess.hide(byHeight: false)
            }
            else {
                viewMoreOrLess.hide(byHeight: true)
                viewLess.hide(byHeight: true)

            }

0

이 솔루션은 런타임시 높이와 너비를 계산하는 데 도움이됩니다.

    let messageText = "Your Text String"
    let size = CGSize.init(width: 250, height: 1000)
    let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
    let estimateFrame = NSString(string: messageText).boundingRect(with:  size, options: options, attributes: [NSAttributedString.Key.font: UIFont(name: "HelveticaNeue", size: 17)!], context: nil)

여기서 문자열의 예상 높이를 계산하여 UILabel 프레임으로 전달할 수 있습니다.

estimateFrame.Width
estimateFrame.Height 

0

스위프트 5 :

UILabel이 있고 boundingRect가 작동하지 않는 경우 (이 문제에 직면했습니다. 항상 1 줄 높이를 반환했습니다) 레이블 크기를 쉽게 계산할 수있는 확장이 있습니다.

extension UILabel {
    func getSize(constrainedWidth: CGFloat) -> CGSize {
        return systemLayoutSizeFitting(CGSize(width: constrainedWidth, height: UIView.layoutFittingCompressedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
    }
}

다음과 같이 사용할 수 있습니다.

let label = UILabel()
label.text = "My text\nIs\nAwesome"
let labelSize = label.getSize(constrainedWidth:200.0)

나를 위해 작동


-2
@IBOutlet weak var constraintTxtV: NSLayoutConstraint!
func TextViewDynamicallyIncreaseSize() {
    let contentSize = self.txtVDetails.sizeThatFits(self.txtVDetails.bounds.size)
    let higntcons = contentSize.height
    constraintTxtV.constant = higntcons
}

5
귀하의 답변은 코드뿐만 아니라 코드에 대한 설명으로 구성되어야합니다. 자세한 내용은 답변 방법을 참조하십시오.
MechMK1

이 코드는 질문에 대답 할 수 있지만,이 코드가 질문에 응답하는 이유 및 / 또는 방법에 대한 추가 컨텍스트를 제공하면 장기적인 가치가 향상됩니다.
Isma

이 답변은 불완전합니다. 그것은 알려지지 않은 중요한 변수를 의미합니다
무너 뜨립니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.