iOS UILabel се свива автоматично, така че думата да не се съкращава до два реда

Опитвам се да накарам UILabel да се свие, така че думите да не се съкращават до следващия ред. Не само отрязване на текст в края на текстовата област.

Ако имам кутия с размери 50x100 и искам да сложа нещо като "American" в кутията на 25.0pt, в крайна сметка получавам:

   50px
 -------
|Ameri- |
|can    |
|Beauty | 100px
|       |
 -------

Свиването на текста изглежда не прави нищо по време на тази ситуация, тъй като все още се побира в рамката на UILabel. Работи доста добре, когато текстът е наистина дълъг като „Шоколадовата фабрика на Уили Уонка“, но не искам съкращаване на думите.

Това е идеалният резултат в този сценарий:

    50px
 --------
[American|
|Beauty  | 100px
|        |
|        |
|        |
 --------

Всички предложения ще бъдат супер оценени!

Редактиране: РЕШЕНИЕ

Ето какво в крайна сметка направих благодарение на предложението в отговора по-долу. Работи чудесно!

- (CGFloat) calculateFromUILabel:(UILabel *)label
{
    NSString *stringToMeasure = label.text;
    NSLog(@"FontSizeMeasurement.calculateFromUILabel() %@", stringToMeasure);

    NSRange range = NSMakeRange(0, 1);
    NSAttributedString *attributedString = label.attributedText;
    NSDictionary *attributes = [attributedString attributesAtIndex:0 effectiveRange:&range];

    NSMutableCharacterSet *characterSet = [[NSCharacterSet whitespaceAndNewlineCharacterSet] mutableCopy];
    [characterSet addCharactersInString:@"-"];
    NSArray *words = [stringToMeasure componentsSeparatedByCharactersInSet:characterSet];

    CGSize maxSize = CGSizeZero;
    NSMutableAttributedString *maxWidthString = nil;
    for(int i = 0; i < words.count; i++) {
        NSString *word = words[i];
        CGSize wordSize = [word sizeWithAttributes:attributes];
        if(wordSize.width > maxSize.width) {
            maxSize = wordSize;
            maxWidthString = [[NSMutableAttributedString alloc] initWithString:word attributes:attributes];
        }
    }

    UIFont *font = [label.font copy];
    while(maxSize.width > self.maxWidth) {
        font = [font fontWithSize:(font.pointSize-0.1)];
        [maxWidthString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, maxWidthString.length)];
        maxSize = [maxWidthString size];
    }

    return font.pointSize;
}

person normmcgarry    schedule 16.04.2014    source източник


Отговори (4)


Не мога да се сетя за нищо, което да е директно вградено. Така че бих предложил:

Разделете низа на компоненти по [NSCharacterSet +whitespaceAndNewlineCharacterSet] и [NSString -componentsSeparatedByCharactersInSet:]. Обмислях да препоръчам NSLinguisticTagger от по-високо ниво, за да извадя цели думи, но това не би позволило неща като думи с двоеточие в края.

От тези думи намерете типографски най-голямата, като използвате добавката UIKit NSString -sizeWithAttributes: (под iOS 7) или -sizeWithFont: (под 6 или по-долу). Ще направите предположението, че най-големият ще остане най-големият, докато намалявате размера на шрифта, което мисля, че винаги ще е вярно, защото Apple не прави агресивно подсказване на шрифта.

Ако тази дума вече е по-малка от ширината на изгледа ви, сте готови. Просто покажете низа.

В противен случай използвайте бързо двоично търсене, като многократно питате за размера, докато намерите по-малкия размер на шрифта, от който се нуждаете, с каквато и да е точност, която смятате за подходяща (0,1 от точка ми звучи разумно, но вие разбирате). След това покажете целия низ в този размер.

person Tommy    schedule 16.04.2014
comment
Хей - наистина оценявам този отговор. Така че препоръчвате ли да намерите най-голямата дума сама по себе си и да преоразмерите надолу, докато тази най-голяма дума стане по-малка от 50px широка? [NSString -sizeWithAttributes: ще ми каже ли CGSize на тази дума при този размер? Това може да свърши работа! Ще го пробвам и ще докладвам. - person normmcgarry; 17.04.2014
comment
Това работи страхотно! Добавих кода за това, което направих, използвайки вашето предложение. Работи като чар. - person normmcgarry; 18.04.2014

Само за добавяне на версия Swift 4 + Добавяне на предпазител, за да го направите само с adjustsFontSizeToFitWidth true, тъй като потребителят, използващ false, няма да иска да се побере с дълга дума, предполагам.

extension UILabel {
// Adjusts the font size to avoid long word to be wrapped
func fitToAvoidWordWrapping() {
    guard adjustsFontSizeToFitWidth else {
        return // Adjust font only if width fit is needed
    }
    guard let words = text?.components(separatedBy: " ") else {
        return // Get array of words separate by spaces
    }

    // I will need to find the largest word and its width in points
    var largestWord: NSString = ""
    var largestWordWidth: CGFloat = 0

    // Iterate over the words to find the largest one
    for word in words {
        // Get the width of the word given the actual font of the label
        let wordWidth = word.size(withAttributes: [.font: font]).width

        // check if this word is the largest one
        if wordWidth > largestWordWidth {
            largestWordWidth = wordWidth
            largestWord = word as NSString
        }
    }

    // Now that I have the largest word, reduce the label's font size until it fits
    while largestWordWidth > bounds.width && font.pointSize > 1 {
        // Reduce font and update largest word's width
        font = font.withSize(font.pointSize - 1)
        largestWordWidth = largestWord.size(withAttributes: [.font: font]).width
    }
}
}
person Dam    schedule 24.11.2017

Направих Swift разширение на UILabel. Просто извикайте метода към етикета, след като са зададени граници и текст.

extension UILabel {

func fitToAvoidWordWrapping(){
    // adjusts the font size to avoid long word to be wrapped

    // get text as NSString
    let text = self.text ?? "" as NSString

    // get array of words separate by spaces
    let words = text.componentsSeparatedByString(" ") as! [NSString]

    // I will need to find the largest word and its width in points
    var largestWord : NSString = ""
    var largestWordWidth : CGFloat = 0

    // iterate over the words to find the largest one
    for word in words{

        // get the width of the word given the actual font of the label
        let wordSize = word.sizeWithAttributes([NSFontAttributeName : self.font])
        let wordWidth = wordSize.width

        // check if this word is the largest one
        if wordWidth > largestWordWidth{
        largestWordWidth = wordWidth
        largestWord = word
        }
    }

    // now that I have the largest word, reduce the label's font size until it fits
    while largestWordWidth > self.bounds.width && self.font.pointSize > 1{

        // reduce font and update largest word's width
        self.font = self.font.fontWithSize(self.font.pointSize - 1)
        let largestWordSize = largestWord.sizeWithAttributes([NSFontAttributeName : self.font])
        largestWordWidth = largestWordSize.width
    }
}
} 
person J.Williams    schedule 15.06.2015

SWIFT 3 превод на горното разширение. Работи като чар!

extension UILabel {

func fitToAvoidWordWrapping(){
    // adjusts the font size to avoid long word to be wrapped

    // get text as NSString
    let text = self.text ?? ("" as NSString) as String

    // get array of words separate by spaces
    let words = text.components(separatedBy: " ")

    // I will need to find the largest word and its width in points
    var largestWord : NSString = ""
    var largestWordWidth : CGFloat = 0

    // iterate over the words to find the largest one
    for word in words{

        // get the width of the word given the actual font of the label
        let wordSize = word.size(attributes: [NSFontAttributeName : self.font])
        let wordWidth = wordSize.width

        // check if this word is the largest one
        if wordWidth > largestWordWidth{
            largestWordWidth = wordWidth
            largestWord = word as NSString
        }
    }

    // now that I have the largest word, reduce the label's font size until it fits
    while largestWordWidth > self.bounds.width && self.font.pointSize > 1{

        // reduce font and update largest word's width
        self.font = self.font.withSize(self.font.pointSize - 1)
        let largestWordSize = largestWord.size(attributes: [NSFontAttributeName : self.font])
        largestWordWidth = largestWordSize.width
    }
}
}
person Pavel Alexandrovich Ak-01    schedule 01.07.2017