Odpowiedzi:
Nie ma sposobu, aby ustawić wyrównanie w pionie na UILabel
, ale można uzyskać ten sam efekt, zmieniając ramkę etykiety. Zrobiłem pomarańczowe etykiety, abyś mógł wyraźnie zobaczyć, co się dzieje.
Oto szybki i łatwy sposób to zrobić:
[myLabel sizeToFit];
Jeśli masz etykietę z dłuższym tekstem, która utworzy więcej niż jedną linię, ustaw numberOfLines
na 0
(zero tutaj oznacza nieograniczoną liczbę linii).
myLabel.numberOfLines = 0;
[myLabel sizeToFit];
Dłuższa wersja
Zrobię etykietę w kodzie, abyś mógł zobaczyć, co się dzieje. Większość tego można również skonfigurować w Konstruktorze interfejsów. Moja konfiguracja to aplikacja oparta na widoku z obrazem tła, który zrobiłem w Photoshopie, aby pokazać marginesy (20 punktów). Etykieta ma atrakcyjny pomarańczowy kolor, dzięki czemu możesz zobaczyć, co się dzieje z wymiarami.
- (void)viewDidLoad
{
[super viewDidLoad];
// 20 point top and left margin. Sized to leave 20 pt at right.
CGRect labelFrame = CGRectMake(20, 20, 280, 150);
UILabel *myLabel = [[UILabel alloc] initWithFrame:labelFrame];
[myLabel setBackgroundColor:[UIColor orangeColor]];
NSString *labelText = @"I am the very model of a modern Major-General, I've information vegetable, animal, and mineral";
[myLabel setText:labelText];
// Tell the label to use an unlimited number of lines
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
[self.view addSubview:myLabel];
}
Pewne ograniczenia w użyciu sizeToFit
wchodzą w grę z tekstem wyrównanym do środka lub do prawej. Oto co się dzieje:
// myLabel.textAlignment = NSTextAlignmentRight;
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
Rozmiar etykiety jest nadal ustalony ze stałym lewym górnym rogiem. Możesz zapisać szerokość oryginalnej etykiety w zmiennej i ustawić ją później sizeToFit
lub nadać jej stałą szerokość, aby przeciwdziałać tym problemom:
myLabel.textAlignment = NSTextAlignmentCenter;
[myLabel setNumberOfLines:0];
[myLabel sizeToFit];
CGRect myFrame = myLabel.frame;
// Resize the frame's width to 280 (320 - margins)
// width could also be myOriginalLabelFrame.size.width
myFrame = CGRectMake(myFrame.origin.x, myFrame.origin.y, 280, myFrame.size.height);
myLabel.frame = myFrame;
Pamiętaj, że sizeToFit
przestrzega minimalnej szerokości początkowej etykiety. Jeśli zaczniesz od etykiety o szerokości 100 i przywołasz sizeToFit
ją, otrzymasz od niej (prawdopodobnie bardzo wysoką) etykietę o szerokości 100 (lub nieco mniejszej). Przed zmianą rozmiaru możesz ustawić minimalną szerokość etykiety.
Kilka innych rzeczy do zapamiętania:
To, czy lineBreakMode
jest przestrzegane, zależy od jego ustawienia. NSLineBreakByTruncatingTail
(domyślne) jest później ignorowane sizeToFit
, podobnie jak pozostałe dwa tryby obcinania (głowa i środek). NSLineBreakByClipping
jest również ignorowane. NSLineBreakByCharWrapping
działa jak zwykle. Szerokość ramki jest nadal zawężona, aby pasowała do skrajnej prawej litery.
Mark Amery naprawił NIB i Storyboardy za pomocą Auto Layout w komentarzach:
Jeśli twoja etykieta jest zawarta w stalówce lub serii ujęć jako widok podrzędny
view
ViewController, który korzysta z autolayout, wówczas włączeniesizeToFit
połączeniaviewDidLoad
nie zadziała, ponieważ autolayout rozmiary i pozycje po podviewachviewDidLoad
są wywoływane i natychmiast cofną efekty twojegosizeToFit
połączenie. Jednak dzwonieniesizeToFit
od wewnątrzviewDidLayoutSubviews
będzie działać.
Wykorzystuje tę NSString
metodę sizeWithFont:constrainedToSize:lineBreakMode:
do obliczenia wysokości ramy potrzebnej do dopasowania łańcucha, a następnie ustawia początek i szerokość.
Zmień rozmiar ramki etykiety, używając tekstu, który chcesz wstawić. W ten sposób możesz pomieścić dowolną liczbę linii.
CGSize maximumSize = CGSizeMake(300, 9999);
NSString *dateString = @"The date today is January 1st, 1999";
UIFont *dateFont = [UIFont fontWithName:@"Helvetica" size:14];
CGSize dateStringSize = [dateString sizeWithFont:dateFont
constrainedToSize:maximumSize
lineBreakMode:self.dateLabel.lineBreakMode];
CGRect dateFrame = CGRectMake(10, 10, 300, dateStringSize.height);
self.dateLabel.frame = dateFrame;
adjustsFontSizeToFitWidth
użyj sizeToFit, a następnie ustaw ramkę etykiety na 0, 0, szerokość, wysokość, etykieta.ramka.size.height (która jest nową wysokością określoną przez sizeToFit), a następnie zastosujadjustsFontSizeToFitWidth
Ustaw nowy tekst:
myLabel.text = @"Some Text"
Ustaw maximum number
linie na 0 (automatycznie):
myLabel.numberOfLines = 0
Ustaw ramkę etykiety na maksymalny rozmiar:
myLabel.frame = CGRectMake(20,20,200,800)
Zadzwoń, sizeToFit
aby zmniejszyć rozmiar ramki, aby zawartość po prostu pasowała:
[myLabel sizeToFit]
Ramka etykiet jest teraz wystarczająco wysoka i wystarczająco szeroka, aby pasowała do tekstu. Lewy górny róg powinien pozostać niezmieniony. Przetestowałem to tylko z tekstem wyrównanym do lewego górnego rogu. W przypadku innych wyrównań może być konieczne zmodyfikowanie ramki później.
Ponadto moja etykieta ma włączone zawijanie słów.
Odnosząc się do rozwiązania rozszerzenia:
for(int i=1; i< newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n"];
powinien zostać zastąpiony przez
for(int i=0; i<newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n "];
Potrzebne jest dodatkowe miejsce w każdej dodanej nowej linii, ponieważ UILabels
zwroty karetki iPhone'a wydają się być ignorowane :(
Podobnie alignBottom również powinien zostać zaktualizowany o @" \n@%"
miejsce "\n@%"
(dla inicjalizacji cyklu należy zastąpić przez „for (int i = 0 ...”).
Działa dla mnie następujące rozszerzenie:
// -- file: UILabel+VerticalAlign.h
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end
// -- file: UILabel+VerticalAlign.m
@implementation UILabel (VerticalAlign)
- (void)alignTop {
CGSize fontSize = [self.text sizeWithFont:self.font];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width; //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight - theStringSize.height) / fontSize.height;
for(int i=0; i<newLinesToPad; i++)
self.text = [self.text stringByAppendingString:@"\n "];
}
- (void)alignBottom {
CGSize fontSize = [self.text sizeWithFont:self.font];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width; //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight - theStringSize.height) / fontSize.height;
for(int i=0; i<newLinesToPad; i++)
self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
@end
Następnie zadzwoń [yourLabel alignTop];
lub [yourLabel alignBottom];
po każdym przypisaniu tekstu swojego etykiety.
VerticalAlign
między nawiasami po @implementation UILabel
. Będąc nowym w Objective-C, nie spotkałem się wcześniej z tą składnią. Jak to się nazywa?
sizeWithFont:constrainedToSize:lineBreakMode:
i sizeWithFont: są amortyzowane w iOS7. Ponadto ta kategoria działa tylko na etykietach, gdy liczbaOpLini jest większa niż 0.
Na wszelki wypadek komuś pomogłem, miałem ten sam problem, ale mogłem go rozwiązać, przechodząc z używania UILabel
na używanie UITextView
. Rozumiem, że nie jest to dla wszystkich, ponieważ funkcjonalność jest nieco inna.
Jeśli przełączysz się na używanie UITextView
, możesz wyłączyć wszystkie właściwości widoku przewijania, a także Włączoną interakcję użytkownika ... To zmusi go do działania bardziej jak etykieta.
UITextView
dało mi od razu pożądany rezultat.
Bez musów, bez zamieszania
@interface MFTopAlignedLabel : UILabel
@end
@implementation MFTopAlignedLabel
- (void)drawTextInRect:(CGRect) rect
{
NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:self.text attributes:@{NSFontAttributeName:self.font}];
rect.size.height = [attributedText boundingRectWithSize:rect.size
options:NSStringDrawingUsesLineFragmentOrigin
context:nil].size.height;
if (self.numberOfLines != 0) {
rect.size.height = MIN(rect.size.height, self.numberOfLines * self.font.lineHeight);
}
[super drawTextInRect:rect];
}
@end
Bez muz, bez Objective-c, bez kłopotów, ale Swift 3:
class VerticalTopAlignLabel: UILabel {
override func drawText(in rect:CGRect) {
guard let labelText = text else { return super.drawText(in: rect) }
let attributedText = NSAttributedString(string: labelText, attributes: [NSFontAttributeName: font])
var newRect = rect
newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height
if numberOfLines != 0 {
newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
}
super.drawText(in: newRect)
}
}
Szybki 4.2
class VerticalTopAlignLabel: UILabel {
override func drawText(in rect:CGRect) {
guard let labelText = text else { return super.drawText(in: rect) }
let attributedText = NSAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font])
var newRect = rect
newRect.size.height = attributedText.boundingRect(with: rect.size, options: .usesLineFragmentOrigin, context: nil).size.height
if numberOfLines != 0 {
newRect.size.height = min(newRect.size.height, CGFloat(numberOfLines) * font.lineHeight)
}
super.drawText(in: newRect)
}
}
Podobnie jak powyższa odpowiedź, ale nie było to w porządku lub łatwo było spoliczkować kod, więc trochę go wyczyściłem. Dodaj to rozszerzenie do własnego pliku .h i .m lub po prostu wklej bezpośrednio nad implementacją, której zamierzasz użyć:
#pragma mark VerticalAlign
@interface UILabel (VerticalAlign)
- (void)alignTop;
- (void)alignBottom;
@end
@implementation UILabel (VerticalAlign)
- (void)alignTop
{
CGSize fontSize = [self.text sizeWithFont:self.font];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width; //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight - theStringSize.height) / fontSize.height;
for(int i=0; i<= newLinesToPad; i++)
{
self.text = [self.text stringByAppendingString:@" \n"];
}
}
- (void)alignBottom
{
CGSize fontSize = [self.text sizeWithFont:self.font];
double finalHeight = fontSize.height * self.numberOfLines;
double finalWidth = self.frame.size.width; //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight - theStringSize.height) / fontSize.height;
for(int i=0; i< newLinesToPad; i++)
{
self.text = [NSString stringWithFormat:@" \n%@",self.text];
}
}
@end
Następnie użyj, umieść tekst na etykiecie, a następnie wywołaj odpowiednią metodę, aby go wyrównać:
[myLabel alignTop];
lub
[myLabel alignBottom];
Jeszcze szybszym (i bardziej brudnym) sposobem na osiągnięcie tego jest ustawienie trybu podziału linii UILabel na „Clip” i dodanie stałej liczby nowych linii.
myLabel.lineBreakMode = UILineBreakModeClip;
myLabel.text = [displayString stringByAppendingString:"\n\n\n\n"];
To rozwiązanie nie będzie działać dla wszystkich - w szczególności, jeśli nadal chcesz wyświetlać „...” na końcu łańcucha, jeśli przekracza on liczbę wyświetlanych wierszy, musisz użyć jednego z dłuższe fragmenty kodu - ale w wielu przypadkach dostaniesz to, czego potrzebujesz.
UILineBreakModeWordWrap
zamiast tego.
Najłatwiejsze podejście przy użyciu Storyboard:
Osadź etykietę w StackView i ustaw następujące dwa atrybuty StackView w Inspektorze atrybutów:
1 Axis
do Horizontal
,
2- Alignment
doTop
UILabel
w jakiejś UIView
podklasie ( UIView
zwykle wystarcza zwykły ) i pozwolić, aby etykieta rosła w dół. Dzięki!
UILabel
i niech StackView wykonywać swoje zadania. Dzięki!
Zamiast tego UILabel
możesz użyć UITextField
opcji wyrównania pionowego:
textField.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
textField.userInteractionEnabled = NO; // Don't allow interaction
Walczyłem z tym przez długi czas i chciałem podzielić się moim rozwiązaniem.
To da ci UILabel
automatyczne odświeżanie tekstu do 0,5 skali i wyśrodkowanie tekstu w pionie. Te opcje są również dostępne w Storyboard / IB.
[labelObject setMinimumScaleFactor:0.5];
[labelObject setBaselineAdjustment:UIBaselineAdjustmentAlignCenters];
Utwórz nową klasę
LabelTopAlign
plik .h
#import <UIKit/UIKit.h>
@interface KwLabelTopAlign : UILabel {
}
@end
plik .m
#import "KwLabelTopAlign.h"
@implementation KwLabelTopAlign
- (void)drawTextInRect:(CGRect)rect {
int lineHeight = [@"IglL" sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, 9999.0f)].height;
if(rect.size.height >= lineHeight) {
int textHeight = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(rect.size.width, rect.size.height)].height;
int yMax = textHeight;
if (self.numberOfLines > 0) {
yMax = MIN(lineHeight*self.numberOfLines, yMax);
}
[super drawTextInRect:CGRectMake(rect.origin.x, rect.origin.y, rect.size.width, yMax)];
}
}
@end
Oto prostsza implementacja, która robi to samo:
#import "KwLabelTopAlign.h"
@implementation KwLabelTopAlign
- (void)drawTextInRect:(CGRect)rect
{
CGFloat height = [self.text sizeWithFont:self.font
constrainedToSize:rect.size
lineBreakMode:self.lineBreakMode].height;
if (self.numberOfLines != 0) {
height = MIN(height, self.font.lineHeight * self.numberOfLines);
}
rect.size.height = MIN(rect.size.height, height);
[super drawTextInRect:rect];
}
@end
sizeToFit
rozwiązań powoduje to UILabel
umieszczenie dowolnego tekstu u góry, nawet jeśli dynamicznie zamieniasz krótszy tekst na dłuższy lub odwrotnie.
W Konstruktorze interfejsów
UILabel
rozmiar największego możliwego tekstuLines
na „0” w Inspektorze atrybutówW twoim kodzie
sizeToFit
na swoją etykietęFragment kodu:
self.myLabel.text = @"Short Title";
[self.myLabel sizeToFit];
W przypadku adaptacyjnego interfejsu użytkownika (iOS8 lub nowszego) wyrównanie w pionie UILabel należy ustawić w StoryBoard, zmieniając właściwości
noOfLines
= 0` i
Ograniczenia
Dostosowywanie ograniczeń UILabel LefMargin, RightMargin i Top Margin.
Zmień
Content Compression Resistance Priority For Vertical
= 1000` Tak, że w pionie> w poziomie.
Edytowane:
noOfLines=0
i następujące ograniczenia są wystarczające do osiągnięcia pożądanych rezultatów.
Utwórz podklasę UILabel. Działa jak marzenie:
// TopLeftLabel.h
#import <Foundation/Foundation.h>
@interface TopLeftLabel : UILabel
{
}
@end
// TopLeftLabel.m
#import "TopLeftLabel.h"
@implementation TopLeftLabel
- (id)initWithFrame:(CGRect)frame
{
return [super initWithFrame:frame];
}
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines
{
CGRect textRect = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines];
textRect.origin.y = bounds.origin.y;
return textRect;
}
-(void)drawTextInRect:(CGRect)requestedRect
{
CGRect actualRect = [self textRectForBounds:requestedRect limitedToNumberOfLines:self.numberOfLines];
[super drawTextInRect:actualRect];
}
@end
Jak omówiono tutaj .
Napisałem funkcję util, aby osiągnąć ten cel. Możesz rzucić okiem:
// dostosuj wysokość etykiety wielowierszowej, aby wyrównała się pionowo do góry + (void) alignLabelWithTop: (UILabel *) etykieta { CGSize maxSize = CGSizeMake (label.frame.size.width, 999); label.adjustsFontSizeToFitWidth = NIE; // uzyskać rzeczywistą wysokość CGSize actualSize = [label.text sizeWithFont: label.font constrainedToSize: maxSize lineBreakMode: label.lineBreakMode]; CGRect rect = label.frame; rect.size.height = actualSize.height; label.frame = rect; }
.Jak używać? (Jeśli lblHello jest tworzony przez Konstruktora interfejsów, pomijam niektóre szczegóły atrybutów UILabel)
lblHello.text = @ "Witaj świecie! Witaj świecie! Witaj świecie! Witaj świecie! Witaj świecie! Witaj świecie! Witaj świecie! Witaj świecie!"; lblHello.numberOfLines = 5; [Utils alignLabelWithTop: lblHello];
Napisałem go również na moim blogu jako artykuł: http://fstoke.me/blog/?p=2819
Poświęciłem trochę czasu na przeczytanie kodu, a także kodu na wprowadzonej stronie, i stwierdziłem, że wszyscy próbują zmodyfikować rozmiar ramki etykiety, aby domyślne wyświetlanie w środku nie było widoczne.
Jednak w niektórych przypadkach chcemy, aby etykieta zajmowała wszystkie te spacje, nawet jeśli etykieta zawiera tak dużo tekstu (np. Wiele wierszy o równej wysokości).
Tutaj użyłem alternatywnego sposobu rozwiązania tego problemu, po prostu wstawiając nowe wiersze na końcu etykiety (proszę zauważyć, że tak naprawdę odziedziczyłem UILabel
, ale nie jest to konieczne):
CGSize fontSize = [self.text sizeWithFont:self.font];
finalHeight = fontSize.height * self.numberOfLines;
finalWidth = size.width; //expected width of label
CGSize theStringSize = [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(finalWidth, finalHeight) lineBreakMode:self.lineBreakMode];
int newLinesToPad = (finalHeight - theStringSize.height) / fontSize.height;
for(int i = 0; i < newLinesToPad; i++)
{
self.text = [self.text stringByAppendingString:@"\n "];
}
Wziąłem tutaj sugestie i stworzyłem widok, który może zawijać UILabel i będzie go dopasowywać i ustawiać liczbę linii, aby był wyrównany do góry. Wystarczy umieścić UILabel jako widok podrzędny:
@interface TopAlignedLabelContainer : UIView
{
}
@end
@implementation TopAlignedLabelContainer
- (void)layoutSubviews
{
CGRect bounds = self.bounds;
for (UILabel *label in [self subviews])
{
if ([label isKindOfClass:[UILabel class]])
{
CGSize fontSize = [label.text sizeWithFont:label.font];
CGSize textSize = [label.text sizeWithFont:label.font
constrainedToSize:bounds.size
lineBreakMode:label.lineBreakMode];
label.numberOfLines = textSize.height / fontSize.height;
label.frame = CGRectMake(0, 0, textSize.width,
fontSize.height * label.numberOfLines);
}
}
}
@end
Możesz użyć TTTAttributLabel , obsługuje wyrównanie w pionie.
@property (nonatomic) TTTAttributedLabel* label;
<...>
//view's or viewController's init method
_label.verticalAlignment = TTTAttributedLabelVerticalAlignmentTop;
Znalazłem, że odpowiedzi na to pytanie są teraz trochę nieaktualne, więc dodaję to dla fanów automatycznych układów.
Auto układ sprawia, że ten problem jest dość trywialny. Zakładając, że dodajemy etykietę UIView *view
, następujący kod to osiągnie:
UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];
[label setText:@"Some text here"];
[label setTranslatesAutoresizingMaskIntoConstraints:NO];
[view addSubview:label];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[label]|" options:0 metrics:nil views:@{@"label": label}]];
[view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[label]" options:0 metrics:nil views:@{@"label": label}]];
Wysokość etykiety zostanie obliczona automatycznie (przy użyciu jej intrinsicContentSize
), a etykieta będzie ustawiona od krawędzi do krawędzi poziomo, na górze view
.
Użyłem wielu powyższych metod i chcę tylko dodać szybkie i brudne podejście:
myLabel.text = [NSString stringWithFormat:@"%@\n\n\n\n\n\n\n\n\n",@"My label text string"];
Upewnij się, że liczba nowych wierszy w ciągu spowoduje, że dowolny tekst zapełni dostępną przestrzeń pionową, i ustaw UILabel, aby obcinał przepełniony tekst.
Ponieważ czasami wystarczająco dobry jest wystarczająco dobry .
UITextView
, że można wywoływać dlopen
w celu obsługi wprowadzania tekstu. Może to powodować duże opóźnienie w wątku interfejsu użytkownika, więc to podejście jest znacznie wydajniejsze!
Chciałem mieć etykietę, która mogłaby mieć wiele linii, minimalny rozmiar czcionki i wyśrodkowana zarówno w poziomie, jak i w pionie w widoku nadrzędnym. Dodałem programowo moją etykietę do mojego widoku:
- (void) customInit {
// Setup label
self.label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)];
self.label.numberOfLines = 0;
self.label.lineBreakMode = UILineBreakModeWordWrap;
self.label.textAlignment = UITextAlignmentCenter;
// Add the label as a subview
self.autoresizesSubviews = YES;
[self addSubview:self.label];
}
A potem, gdy chciałem zmienić tekst mojej wytwórni ...
- (void) updateDisplay:(NSString *)text {
if (![text isEqualToString:self.label.text]) {
// Calculate the font size to use (save to label's font)
CGSize textConstrainedSize = CGSizeMake(self.frame.size.width, INT_MAX);
self.label.font = [UIFont systemFontOfSize:TICKER_FONT_SIZE];
CGSize textSize = [text sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
while (textSize.height > self.frame.size.height && self.label.font.pointSize > TICKER_MINIMUM_FONT_SIZE) {
self.label.font = [UIFont systemFontOfSize:self.label.font.pointSize-1];
textSize = [ticker.blurb sizeWithFont:self.label.font constrainedToSize:textConstrainedSize];
}
// In cases where the frame is still too large (when we're exceeding minimum font size),
// use the views size
if (textSize.height > self.frame.size.height) {
textSize = [text sizeWithFont:self.label.font constrainedToSize:self.frame.size];
}
// Draw
self.label.frame = CGRectMake(0, self.frame.size.height/2 - textSize.height/2, self.frame.size.width, textSize.height);
self.label.text = text;
}
[self setNeedsDisplay];
}
Mam nadzieję, że komuś pomoże!
FXLabel (na github) robi to od razu po ustawieniu label.contentMode
na UIViewContentModeTop
. Ten komponent nie jest tworzony przeze mnie, ale jest to komponent, z którego często korzystam, ma mnóstwo funkcji i wydaje się działać dobrze.
dla każdego, kto to czyta, ponieważ tekst wewnątrz etykiety nie jest wyśrodkowany pionowo, należy pamiętać, że niektóre typy czcionek nie są projektowane jednakowo. na przykład, jeśli utworzysz etykietę o rozmiarze zapfino 16, zobaczysz, że tekst nie jest idealnie wyśrodkowany w pionie.
jednak praca z helvetica spowoduje wyśrodkowanie tekstu w pionie.
Zastosowanie textRect(forBounds:limitedToNumberOfLines:)
.
class TopAlignedLabel: UILabel {
override func drawText(in rect: CGRect) {
let textRect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
super.drawText(in: textRect)
}
}
Podklasę UILabel i ograniczanie prostokąta rysunkowego:
- (void)drawTextInRect:(CGRect)rect
{
CGSize sizeThatFits = [self sizeThatFits:rect.size];
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
[super drawTextInRect:rect];
}
Wypróbowałem rozwiązanie polegające na dodawaniu nowego wiersza i w niektórych przypadkach napotkałem nieprawidłowe zachowanie. Z mojego doświadczenia wynika, że łatwiej jest ograniczyć rysowanie jak wyżej niż bałagan numberOfLines
.
PS Możesz sobie wyobrazić łatwą obsługę UIViewContentMode w ten sposób:
- (void)drawTextInRect:(CGRect)rect
{
CGSize sizeThatFits = [self sizeThatFits:rect.size];
if (self.contentMode == UIViewContentModeTop) {
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
}
else if (self.contentMode == UIViewContentModeBottom) {
rect.origin.y = MAX(0, rect.size.height - sizeThatFits.height);
rect.size.height = MIN(rect.size.height, sizeThatFits.height);
}
[super drawTextInRect:rect];
}
Dopóki nie wykonujesz żadnego złożonego zadania, możesz użyć UITextView
zamiast niego UILabels
.
Wyłącz przewijanie.
Jeśli chcesz, aby tekst był wyświetlany całkowicie, po prostu użytkownik sizeToFit
i sizeThatFits:
metody
W krótkim
let myLabel : UILabel!
Aby tekst etykiety był dopasowany do ekranu i znajduje się na górze
myLabel.sizeToFit()
Aby dopasować czcionkę etykiety do szerokości ekranu lub określonego rozmiaru.
myLabel.adjustsFontSizeToFitWidth = YES
i trochę tekstu Wyrównanie etykiety:
myLabel.textAlignment = .center
myLabel.textAlignment = .left
myLabel.textAlignment = .right
myLabel.textAlignment = .Natural
myLabel.textAlignment = .Justified
[myLabel sizeToFit]
. Dziękuję Ci!
To stare rozwiązanie, użyj autolayout na iOS> = 6
Moje rozwiązanie:
@interface UITopAlignedLabel : UILabel
@end
@implementation UITopAlignedLabel
#pragma mark Instance methods
- (NSArray*)splitTextToLines:(NSUInteger)maxLines {
float width = self.frame.size.width;
NSArray* words = [self.text componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableArray* lines = [NSMutableArray array];
NSMutableString* buffer = [NSMutableString string];
NSMutableString* currentLine = [NSMutableString string];
for (NSString* word in words) {
if ([buffer length] > 0) {
[buffer appendString:@" "];
}
[buffer appendString:word];
if (maxLines > 0 && [lines count] == maxLines - 1) {
[currentLine setString:buffer];
continue;
}
float bufferWidth = [buffer sizeWithFont:self.font].width;
if (bufferWidth < width) {
[currentLine setString:buffer];
}
else {
[lines addObject:[NSString stringWithString:currentLine]];
[buffer setString:word];
[currentLine setString:buffer];
}
}
if ([currentLine length] > 0) {
[lines addObject:[NSString stringWithString:currentLine]];
}
return lines;
}
- (void)drawRect:(CGRect)rect {
if ([self.text length] == 0) {
return;
}
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, self.textColor.CGColor);
CGContextSetShadowWithColor(context, self.shadowOffset, 0.0f, self.shadowColor.CGColor);
NSArray* lines = [self splitTextToLines:self.numberOfLines];
NSUInteger numLines = [lines count];
CGSize size = self.frame.size;
CGPoint origin = CGPointMake(0.0f, 0.0f);
for (NSUInteger i = 0; i < numLines; i++) {
NSString* line = [lines objectAtIndex:i];
if (i == numLines - 1) {
[line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeTailTruncation];
}
else {
[line drawAtPoint:origin forWidth:size.width withFont:self.font lineBreakMode:UILineBreakModeClip];
}
origin.y += self.font.lineHeight;
if (origin.y >= size.height) {
return;
}
}
}
@end