2016-11-04 2 views
0

В моем приложении у меня есть UILabel с двумя предустановленными строками. Я могу установить выравнивание текста либо .left, либо .justified.Динамически настроенное выравнивание текста UILabel между .left и .justified

Если я установил его на .left, при наличии достаточного пространства между последним словом в строке и максимальной позицией x метки метки нет. Тем не менее, когда пространства не так много, так что последнее слово находится очень близко к максимальной позиции x, оно выглядит странно, потому что оно не точно выровнено по правому краю (как это было бы с .justified.

Если я установите его на .justified, он всегда хорошо выровнен, но иногда расстояние между отдельными символами выглядит странно.

То, что я ищу, - это способ динамической корректировки выравнивания текста в зависимости от расстояния между последним словом в первая строка до максимальной позиции x метки. Скажем, если позиция последнего символа последнего слова меньше 50, я хочу иметь выравнивание текста .left, в противном случае я хотел бы иметь .justified. вес ай, как это сделать?

+1

Isnt это просто вопрос использования NSAttributedString для измерения ширины текста? –

ответ

0

Я принял довольно хакерский подход, который требует некоторой вычислительной мощности, но, похоже, он работает.


Прежде всего, я извлечь строку в первой строке этикетки с помощью этого расширения:

import CoreText 

extension UILabel { 

    /// Returns the String displayed in the first line of the UILabel or "" if text or font is missing 
    var firstLineString: String { 

    guard let text = self.text else { return "" } 
    guard let font = self.font else { return "" } 
    let rect = self.frame 

    let attStr = NSMutableAttributedString(string: text) 
    attStr.addAttribute(String(kCTFontAttributeName), value: CTFontCreateWithName(font.fontName as CFString, font.pointSize, nil), range: NSMakeRange(0, attStr.length)) 

    let frameSetter = CTFramesetterCreateWithAttributedString(attStr as CFAttributedString) 
    let path = CGMutablePath() 
    path.addRect(CGRect(x: 0, y: 0, width: rect.size.width + 7, height: 100)) 
    let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, nil) 

    guard let line = (CTFrameGetLines(frame) as! [CTLine]).first else { return "" } 
    let lineString = text[text.startIndex...text.index(text.startIndex, offsetBy: CTLineGetStringRange(line).length-2)] 

    return lineString 
    } 
} 

После этого я рассчитать ширину, этикетку с линией номером 1 и фиксированная высота будет требуется для этой строки, используя это расширение:

extension UILabel { 

    /// Get required width for a UILabel depending on its text content and font configuration 
    class func calculateWidth(text: String, height: CGFloat, font: UIFont) -> CGFloat { 

     let label = UILabel(frame: CGRect(x: 0, y: 0, width: CGFloat.greatestFiniteMagnitude, height: height)) 
     label.numberOfLines = 1 
     label.font = font 
     label.text = text 
     label.sizeToFit() 

     return label.frame.size.width 
    } 
} 

Основываясь на том, что я могу вычислить расстояние вправо и решить, следует ли выбрать выравнивание текста .left или .justified, поэтому основной код выглядит следующим образом:

// Set text 
myLabel.text = someString 

// Change text alignment depending on distance to right 
let firstLineString = myLabel.firstLineString 
let distanceToRight = myLabel.frame.size.width - UILabel.calculateWidth(text: firstLineString, height: myLabel.frame.size.height, font: myLabel.font) 
myLabel.textAlignment = distanceToRight < 20 ? .justified : .left 
Смежные вопросы