Swift、UILabelで表示する文字列の高さを取得する

UILabelの高さ取得に気をつけること

1. xibやstoryboradの指定したFontと、プログラムで指定しているフォントは同じかどうか
2. viewDidLoad時ではまだviewのサイズが決まっていない

ロジック

NSString
func boundingRectWithSize(size: CGSize, options: NSStringDrawingOptions, attributes: [NSObject : AnyObject]!, context: NSStringDrawingContext!) -> CGRect

NSAttributedString
func boundingRectWithSize(size: CGSize, options: NSStringDrawingOptions, context: NSStringDrawingContext?) -> CGRect


どちらも使い方は同じ、必要な最大領域、オプションを指定すれば、描画に必要なサイズが取得可能

サンプル

NSString

    func heightWithText(text: String) -> CGFloat {
       
        let horizonMergin:CGFloat = 32
        let verticalMergin:CGFloat = 32
        
        let maxSize = CGSize(width: CGRectGetWidth(UIScreen.mainScreen().bounds) - horizonMergin, height: CGFloat.max)
        let options = unsafeBitCast(
            NSStringDrawingOptions.UsesLineFragmentOrigin.rawValue |
            NSStringDrawingOptions.UsesFontLeading.rawValue,
            NSStringDrawingOptions.self)
        
        // ここは必要に応じて
        var paragrahStyle = NSMutableParagraphStyle()
        paragrahStyle.lineHeightMultiple = 1.3
        paragrahStyle.lineSpacing = 4

        let font = UIFont.systemFontOfSize(14.0)
        var attributes = [NSFontAttributeName:font,
            NSParagraphStyleAttributeName:paragrahStyle]
        
        let frame = text.boundingRectWithSize(maxSize,
            options: options,
            attributes: attributes,
            context: nil)
        let height = ceil(frame.size.height) + verticalMergin
        
        return height
    }

NSAttributedString

    class func heightWithText(text: String) -> CGFloat {
        
        let horizonMergin:CGFloat = 32
        let verticalMergin:CGFloat = 32
        
        var attr = NSMutableAttributedString(string: text)
        
        var paragrahStyle = NSMutableParagraphStyle()
        paragrahStyle.lineHeightMultiple = 1.3
        paragrahStyle.lineSpacing = 4
        
        attr.addAttribute(NSParagraphStyleAttributeName, value: paragrahStyle, range: NSMakeRange(0, attr.length))
        
        
        let maxSize = CGSize(width: CGRectGetWidth(UIScreen.mainScreen().bounds) - horizonMergin, height: CGFloat.max)
        let options = unsafeBitCast(
            NSStringDrawingOptions.UsesLineFragmentOrigin.rawValue |
                NSStringDrawingOptions.UsesFontLeading.rawValue,
            NSStringDrawingOptions.self)
        
        let font = UIFont.systemFontOfSize(14.0)
        attr.addFontAttribute(font, range: NSRange(location: 0, length: attr.length))
        
        let frame = attr.boundingRectWithSize(maxSize,
            options: options,
            context: nil)
        let height = ceil(frame.size.height) + verticalMergin
        
        return height
    }

パフォーマンス

NSString : 0.000555038452148438 0.000557005405426025
NSAttributedString : 0.000142991542816162 0.000165998935699463

パフォーマンスはNSAttributedStringの方が早いです。

0 件のコメント:

コメントを投稿

ReactNativeでAndroid対応する話

前提 ReactNativeでiOS版のアプリをリリースしていて、Android版をリリースする話 トラブルシューティング Build.VERSION_CODES.Q が存在しないエラー compileSdkVersionを29以上にすると解決 メモリー足りないエラー Execu...