Как выровнять базовые линии текста в UILabels с разными размерами шрифтов на iOS? - PullRequest
18 голосов
/ 28 марта 2012

Мне нужно выровнять базовые линии текста в 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 выровнены, базовые линии текста смещены с небольшим запасом. Как я могу выровнять базовые линии текста динамически (потому что размеры шрифта могут измениться во время выполнения)?

Ответы [ 4 ]

25 голосов
/ 31 января 2013

Я использовал этот ответ в нескольких разных местах, но на экранах 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;
9 голосов
/ 07 февраля 2013

Вы можете получить идеальное выравнивание по пикселям базовой линии для любой пары 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 голосов
/ 30 мая 2012

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

Мне нужно было сделать это только с двумя разными метками, и я делаю это в подклассе 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;
}
0 голосов
/ 07 августа 2018

После iOS9 . С помощью автоматического размещения UILabel имеет привязку под названием: lastBaselineAnchor . Например:

hintLabel.lastBaselineAnchor.constraint(equalTo: titleLabel.lastBaselineAnchor).isActive = true
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...