Как выровнять исходные тексты в UILabels с разными размерами шрифтов на iOS?

Мне нужно выровнять исходные тексты в UILabels. То, что я сейчас делаю, - это выравнивание базовых линий UILabels, содержащих текст, и когда размер шрифта текста в двух ярлыках отличается от другого, это приводит к выравниванию исходной линии UILabels, но несогласованной исходной базой текста (несогласованной с небольшим отрывом, но все же перекос). Этикетки включены в пользовательский подкласс UIView, поэтому self относится к охватывающему UIView.

вот соответствующий код

[self.mySmallLabel sizeToFit];
[self.myBigLabel sizeToFit];

self.mySmallLabel.frame = CGRectMake(0,     
                                     self.bounds.size.height - self.mySmallLabel.bounds.size.height, 
                                     self.mySmallLabel.bounds.size.width, 
                                     self.mySmallLabel.bounds.size.height);

self.myBigLabel.frame = CGRectMake(self.mySmallLabel.frame.origin.x + self.mySmallLabel.bounds.size.width, 
                                   self.bounds.size.height - self.myBigLabel.bounds.size.height, 
                                   self.myBigLabel.bounds.size.width, 
                                   self.myBigLabel.bounds.size.height);
[self.mySmallLabel sizeToFit];
[self.myBigLabel sizeToFit];

Этот код приводит к смещению изображения, указанного ниже.

Misalignemnt

Как вы можете видеть, хотя исходные линии UILabel выровнены, исходные тексты текста смещены с небольшим отрывом. Как можно динамически выровнять исходные тексты (поскольку размер шрифта может измениться во время выполнения)?

Ответы

Ответ 1

Я использовал этот ответ в нескольких разных местах, но исходные линии иногда отображались на дисплеях Retina. Ниже приведен фрагмент ниже:

[majorLabel sizeToFit];
[minorLabel sizeToFit];

CGRect changedFrame = minorLabel.frame;
changedFrame.origin.x = CGRectGetWidth(majorLabel.frame);

const CGFloat scale = [UIScreen mainScreen].scale;
const CGFloat majorLabelBaselineInSuperView = CGRectGetMaxY(majorLabel.frame) + majorLabel.font.descender;
const CGFloat minorLabelBaselineInOwnView = CGRectGetHeight(minorLabel.frame) + minorLabel.font.descender;
changedFrame.origin.y = ceil((majorLabelBaselineInSuperView - minorLabelBaselineInOwnView) * scale) / scale;

minorLabel.frame = changedFrame;

Ответ 2

Вы можете получить идеальное выравнивание по пикселям для любой пары UILabels, используя значение высоты подписи UIFont в простом вычислении. Вот как:

[majorLabel sizeToFit];
[minorLabel sizeToFit];

CGRect changedFrame = minorLabel.frame;
changedFrame.origin.y = ceilf(majorLabel.frame.origin.y + (majorLabel.font.ascender - minorLabel.font.ascender));
minorLabel.frame = changedFrame;

ceilf() используется, потому что значения font.ascender могут быть дробными.

Я тестировал это как на сетчатке, так и на устройствах, не содержащих сетчатки, с отличными результатами. Позиционирование двух меток относительно друг друга по оси X было опущено, так как ваши потребности могут отличаться. Если вам нужно краткое объяснение того, что означает подшивка UIFont (плюс другая информация UIFont), посмотрите эту четкую, сжатую статью .

Ответ 3

Я хотел сделать это сам (сейчас) и нашел свой ответ на почти идентичном вопросе. Это не простое решение, но мы должны делать математику.

Мне нужно было только сделать это с помощью двух разных меток, и я делаю это в подклассе UIView.

- (void)layoutSubviews {
    [majorLabel sizeToFit];
    [minorLabel sizeToFit];

    CGRect changedFrame = minorLabel.frame;
    changedFrame.origin.x = majorLabel.frame.size.width;
    changedFrame.origin.y = (majorLabel.frame.size.height + majorLabel.font.descender) - (minorLabel.frame.size.height + minorLabel.font.descender);
    minorLabel.frame = changedFrame;
}