2016-04-02 4 views
0

Пользовательских этикеток, которая изменяет По его Содержимому

Я делаю ярлык с нуля. (Моя цель состоит в том, чтобы сделать вертикальную текстовую метку для монгольского скрипта, но пока я просто делаю обычную горизонтальную текстовую метку как практику.)Как сделать кадр пользовательского представления в соответствии его instrinsic размера содержимого

До тех пор, пока нет ограничений длины и ширины, фрейма метки для изменения размера в соответствии с его внутренним размером содержимого.

Он работает в IB

В IB все, кажется, работает хорошо, когда я испытываю UILabel, мой заказ ярлык (а UIView подкласс), и кнопка.

Я добавляю верхние и ведущие ограничения для каждого из этих видов, но не устанавливаю ограничений по высоте или ширине.

enter image description here

Если я изменить их на раскадровке (но без добавления каких-либо ограничений) больше ...

enter image description here

И затем выберите Frames Update для Все Представления в View Контроллер, нормальная метка и мой пользовательский ярлык, как правильно изменяются, так и сами по себе.

enter image description here

Это не работает на Running App

При изменении текста метки во время выполнения, хотя, рамки моего пользовательского ярлыка не изменение размера. (Я временно добавил темно-синюю границу к текстовому слою, чтобы помочь отличить его здесь от рамы на заказ ярлык, который является светло-голубой цвет фона.)

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 делает это Я отсутствую в своем пользовательском ярлыке? I overrode 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 говорит

Зова это когда что-то меняется в пользовательском мнении, что лишает законную силу присущего размера содержимого. Это позволяет использовать схему макета с ограничениями, чтобы принять новый размер встроенного контента в следующем проходе .

Где я нашел это решение: