Как получить автоматически отрегулированный размер шрифта в iOS 7.0 или новее?

Я хочу получить размер шрифта некоторого текста после его уменьшения в UILabel или UITextField. Это было возможно до iOS 7.0: Как получить автоматически скорректированный размер шрифта UILabel (UITextView)?. Тем не менее, sizeWithFont устарел в iOS 7.0. Я попытался использовать его замену, sizeWithAttributes, но без успеха. Есть ли способ сделать это в iOS 7.0?

Ответ 1

Здесь функция, которую я сделал, чтобы получить скорректированный размер шрифта UILabel:

Swift

func getApproximateAdjustedFontSizeWithLabel(label: UILabel) -> CGFloat {

    if label.adjustsFontSizeToFitWidth == true {

        var currentFont: UIFont = label.font
        let originalFontSize = currentFont.pointSize
        var currentSize: CGSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])

        while currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor) {
            currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
            currentSize = (label.text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
        }

        return currentFont.pointSize

    }
    else {

        return label.font.pointSize

    }

}

Objective-C

- (CGFloat)getApproximateAdjustedFontSizeWithLabel:(UILabel *)label {

    if (label.adjustsFontSizeToFitWidth) {

        UIFont *currentFont = label.font;
        CGFloat originalFontSize = currentFont.pointSize;
        CGSize currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];

        while (currentSize.width > label.frame.size.width && currentFont.pointSize > (originalFontSize * label.minimumScaleFactor)) {
            currentFont = [currentFont fontWithSize:currentFont.pointSize - 1];
            currentSize = [label.text sizeWithAttributes:@{NSFontAttributeName : currentFont}];
        }

        return currentFont.pointSize;
    }
    else {

        return label.font.pointSize;
    }
}

Ответ 2

Мне очень понравился @WaltersGE1 ответ, поэтому я сделал его расширением для UILabel, чтобы сделать его еще более удобным для использования:

extension UILabel {

    /// The receiver’s font size, including any adjustment made to fit to width. (read-only)
    ///
    /// If `adjustsFontSizeToFitWidth` is not `true`, this is just an alias for
    /// `.font.pointSize`. If it is `true`, it returns the adjusted font size.
    ///
    /// Derived from: [http://stackoverflow.com/a/28285447/5191100](http://stackoverflow.com/a/28285447/5191100)
    var fontSize: CGFloat {
        get {
            if adjustsFontSizeToFitWidth {
                var currentFont: UIFont = font
                let originalFontSize = currentFont.pointSize
                var currentSize: CGSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])

                while currentSize.width > frame.size.width && currentFont.pointSize > (originalFontSize * minimumScaleFactor) {
                    currentFont = currentFont.fontWithSize(currentFont.pointSize - 1)
                    currentSize = (text! as NSString).sizeWithAttributes([NSFontAttributeName: currentFont])
                }

                return currentFont.pointSize
            }

            return font.pointSize
        }
    }
}

Ответ 3

Проверьте, был ли применен текст (возможно, сначала перезагрузите представление), вы можете захватить размер шрифта. Например, с помощью UITextField вы можете реализовать метод делегирования для textDidChange, а затем узнать размер шрифта из атрибута font на текстовом поле. Для ярлыка вы можете обновить текст, затем проверить размер шрифта.

Пример. Я построил проект, который обновил UILabel из UITextField

-(void)textFieldDidEndEditing:(UITextField *)textField{

   self.label.text = textField.text;

    CGSize initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
    while ( initialSize.width > _label.frame.size.width ) {
        [_label setFont:[_label.font fontWithSize:_label.font.pointSize - 1]];
        initialSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
    }
    CGFloat actualSize = _label.font.pointSize;
    NSLog(@"acutal size %f",actualSize );
}

Фактический размер кажется правильным. (источник расчета размера)

Ответ 4

Все решения до сих пор предполагают целочисленные размеры шрифтов и не соответствуют свойству UILabel minimumScaleFactor.

Что-то вроде этого должно работать:

+ (CGFloat)fontSizeForLabel:(UILabel *)label 
{
    if (label.adjustsFontSizeToFitWidth == NO || label.minimumScaleFactor >= 1.f) {
        // font adjustment is disabled
        return label.font.pointSize;
    }

    CGSize unadjustedSize = [_label.text sizeWithAttributes:@{NSFontAttributeName:_label.font}];
    CGFloat scaleFactor = label.frame.size.width / unadjustedSize.width;

    if (scaleFactor >= 1.f) {
        // the text already fits at full font size
        return label.font.pointSize;
    }

    // Respect minimumScaleFactor
    scaleFactor = MAX(scaleFactor, minimumScaleFactor);

    CGFloat newFontSize = label.font.pointSize * scaleFactor;

    // Uncomment this if you insist on integer font sizes
    //newFontSize = floor(newFontSize);

    return newFontSize;
}