Подтвердить что ты не робот

Верхний выравнивающий текст разных размеров в пределах UILabel

Как выровнять текст разных размеров в UILabel? Примером является верхняя выровняемость меньшего размера в процентах с баннерами с большими размерами в долларах.

Sample Image

UILabel в iOS6 поддерживает NSAttributedString, что позволяет мне иметь текст разных размеров в одном и том же UILabel. Однако он не имеет атрибута для выравнивания текста. Каковы варианты реализации этого? Мне кажется, что предоставление пользовательской логики рисования для создания верхнего выравнивания на основе настраиваемого строкового ключа может быть лучшим, но я не знаю, как это сделать.

4b9b3361

Ответ 1

Я смог достичь желаемого результата с помощью одной метки.

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

- (NSMutableAttributedString *)styleSalePriceLabel:(NSString *)salePrice withFont:(UIFont *)font
{
    if ([salePrice rangeOfString:@"."].location == NSNotFound) {
        return [[NSMutableAttributedString alloc] initWithString:salePrice];
    } else {
        NSRange range = [salePrice rangeOfString:@"."];
        range.length = (salePrice.length - range.location);
        NSMutableAttributedString *stylizedPriceLabel = [[NSMutableAttributedString alloc] initWithString:salePrice];
        UIFont *smallFont = [UIFont fontWithName:font.fontName size:(font.pointSize / 2)];
        NSNumber *offsetAmount = @(font.capHeight - smallFont.capHeight);
        [stylizedPriceLabel addAttribute:NSFontAttributeName value:smallFont range:range];
        [stylizedPriceLabel addAttribute:NSBaselineOffsetAttributeName value:offsetAmount range:range];
        return stylizedPriceLabel;
    }
}

Это дает следующее:

Ответ 2

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

К счастью, UIFont дает нам всю информацию, необходимую нам для этого. Нам нужно измерить пустое пространство прожектора, которое используют эти метки, и отрегулировать относительное позиционирование для его учета, например:

//Make sure the labels hug their contents
[self.bigTextLabel sizeToFit];
[self.smallTextLabel sizeToFit];

//Figure out the "blank" space above normal character height for the big text
UIFont *bigFont = self.bigTextLabel.font;
CGFloat bigAscenderSpace = (bigFont.ascender - bigFont.capHeight);

//Move the small text down by that ammount
CGFloat smallTextOrigin = CGRectGetMinY(self.bigTextLabel.frame) + bigAscenderSpace;

//Figure out the "blank" space above normal character height for the little text
UIFont *smallFont = self.smallTextLabel.font;
CGFloat smallAscenderSpace = smallFont.ascender - smallFont.capHeight;

//Move the small text back up by that ammount
smallTextOrigin -= smallAscenderSpace;

//Actually assign the frames
CGRect smallTextFrame = self.smallTextLabel.frame;
smallTextFrame.origin.y = smallTextOrigin;
self.smallTextLabel.frame = smallTextFrame;

(Этот код предполагает, что у вас есть два свойства метки с именем bigTextLabel и smallTextLabel, соответственно)


Edit:

Выполнение этого без двух меток довольно похоже. Вы можете создать пользовательский подкласс UIView и нарисовать NSAttributedStrings в нем с помощью метода -drawInRect:options:context: (обязательно используйте NSStringDrawingUsesLineFragmentOrigin в своих опциях). Математика для разработки верхнего выравнивания должна быть одинаковой, с той лишь разницей, что вы получаете шрифт из атрибутной строки через атрибут NSFontAttributeName, а не метку. Видео 2012 WWDC по атрибуту строкового рисунка является хорошей ссылкой для этого.

Ответ 3

Это слишком плохо. У меня недостаточно репутации, чтобы прокомментировать ответ, который я использовал хорошо после небольшой модификации. Я просто хочу указать, что используйте smallfont для центов вместо font, что может быть опечаткой.

Ниже приведен модифицированный код

- (NSMutableAttributedString *)styleSalePriceLabel:(NSString *)salePrice withFont:(UIFont *)font
{
    if ([salePrice rangeOfString:@"."].location == NSNotFound) {
        return [[NSMutableAttributedString alloc]  
                   initWithString:salePrice];
    } else {
        NSRange range = [salePrice rangeOfString:@"."];
        range.length = (salePrice.length - range.location);
        NSMutableAttributedString *stylizedPriceLabel =
            [[NSMutableAttributedString alloc] initWithString:salePrice];
        UIFont *smallfont = [UIFont fontWithName:font.fontName 
                                            size:(font.pointSize / 2)];
        NSNumber *offsetAmount = @(font.capHeight - smallfont.capHeight);
        [stylizedPriceLabel addAttribute:NSFontAttributeName 
                                   value:smallfont 
                                   range:range];
        [stylizedPriceLabel addAttribute:NSBaselineOffsetAttributeName 
                                   value:offsetAmount 
                                   range:range];
        return stylizedPriceLabel;
    }
}

Ответ 4

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

CGRect labelFrame;
//Set the origin of the label to whatever you want
labelFrame.size = [label.text sizeWithFont:label.font];  //If using NSString
labelFrame.size = [label.text size];                     //If using NSAttributedString
label.frame = labelFrame;

См. эту аналогичную публикацию SO для более подробной информации.