2016-04-02 90 views
0

根據其內容調整大小的自定義標籤

我從頭開始創建標籤。 (我的最終目的是爲蒙古文腳本製作一個垂直文本標籤,但現在我只是製作一個普通的水平文本標籤作爲練習。)如何使自定義視圖的框架匹配其內在內容大小

只要沒有長度和寬度約束,我想要我的自定義標籤的框架根據其內在內容大小來調整大小。

它工作在IB

在IB一切似乎當我測試一個UILabel,我的自定義標籤(一個UIView子類)進行精細的工作,和一個按鈕。

我向這些視圖中的每一個添加了頂部和主要約束,但不設置任何高度或寬度約束。

enter image description here

如果我調整他們的故事板(但仍然沒有增加任何更多的限制)...

enter image description here

,然後選擇更新框架在查看全部查看控制器,正常標籤和我的自定義標籤都正確調整其內在內容大小。

enter image description here

它不正在運行的應用程序

工作時,我在運行時更改標籤的文本,但是,我的自定義標籤的框架不會改變大小。 (我暫時增加了一個深藍色的邊框文字層,以幫助從自定義標籤的框架,這是淡藍色背景色在這裏區分。)

enter image description here

單擊「更改文本」給出

enter image description here

正如您所看到的,文本圖層框架已更改,但自定義視圖的框架沒有更改。

代碼

這是我的自定義標籤類:

import UIKit 
@IBDesignable 
class UILabelFromScratch: UIView { 

    private let textLayer = CATextLayer() 

    @IBInspectable var text: String = "" { 
     didSet { 
      updateTextLayerFrame() 
     } 
    } 

    @IBInspectable var fontSize: CGFloat = 17 { 
     didSet { 
      updateTextLayerFrame() 
     } 
    } 

    // MARK: - Initialization 

    override init(frame: CGRect) { 
     super.init(frame: frame) 
     setup() 
    } 

    required init?(coder: NSCoder) { 
     super.init(coder: coder) 
     setup() 
    } 

    func setup() { 

     // Text layer 
     textLayer.borderColor = UIColor.blueColor().CGColor 
     textLayer.borderWidth = 1 
     textLayer.contentsScale = UIScreen.mainScreen().scale 
     layer.addSublayer(textLayer) 
    } 

    // MARK: Other methods 

    override func intrinsicContentSize() -> CGSize { 
     return textLayer.frame.size 
    } 

    func updateTextLayerFrame() { 

     let myAttribute = [ NSFontAttributeName: UIFont.systemFontOfSize(fontSize) ] 
     let attrString = NSMutableAttributedString(string: self.text, attributes: myAttribute) 
     let size = dimensionsForAttributedString(attrString) 

     textLayer.frame = CGRect(x: self.layer.bounds.origin.x, y: self.layer.bounds.origin.y, width: size.width, height: size.height) 
     textLayer.string = attrString 

    } 

    func dimensionsForAttributedString(attrString: NSAttributedString) -> CGSize { 

     var ascent: CGFloat = 0 
     var descent: CGFloat = 0 
     var width: CGFloat = 0 
     let line: CTLineRef = CTLineCreateWithAttributedString(attrString) 
     width = CGFloat(CTLineGetTypographicBounds(line, &ascent, &descent, nil)) 

     // make width an even integer for better graphics rendering 
     width = ceil(width) 
     if Int(width)%2 == 1 { 
      width += 1.0 
     } 

     return CGSize(width: width, height: ceil(ascent+descent)) 
    } 
} 

這裏是視圖控制器類:

import UIKit 
class ViewController: UIViewController { 

    @IBOutlet weak var normalLabel: UILabel! 
    @IBOutlet weak var labelFromScratch: UILabelFromScratch! 

    @IBAction func changeTextButtonTapped(sender: UIButton) { 

     normalLabel.text = "Hello" 
     labelFromScratch.text = "Hello" 
    } 
} 

問題

它是什麼,UILabel這是否我錯過了我的自定義標籤?我覆蓋intrinsicContentSize

override func intrinsicContentSize() -> CGSize { 
    return textLayer.frame.size 
} 

我還需要做什麼?

回答

1

我是缺少的一行代碼:

invalidateIntrinsicContentSize() 

我更新文本層幀之後加入它。

func updateTextLayerFrame() { 

    // ... 

    textLayer.frame = CGRect(x: self.layer.bounds.origin.x, y: self.layer.bounds.origin.y, width: size.width, height: size.height) 
    invalidateIntrinsicContentSize() 

    // ... 
} 

documentation

調用此當事情在無效 其內在含量的大小自定義視圖改變。這允許基於約束的佈局 系統在其下一個 佈局階段考慮新的固有內容大小。

,我發現這個解決方案:

相關問題