2012-10-31 3 views
29

Mam widok, który zawiera tylko UILabel. Ta etykieta zawiera tekst wielowierszowy. Rodzic ma zmienną szerokość, którą można zmienić za pomocą gestu panoramowania. Mój problem polega na tym, że kiedy to robię, zmiana rozmiaru UILabel nie przelicza jego wysokości tak, że cała zawartość jest nadal widoczna, po prostu ją odcina.Funkcja Autolayout na iOS: Problem z UILabels w widoku rozmiaru rodzica

udało mi się go naprawić przy odrobinie hack, ale to jest strasznie powolny, aby uruchomić:

- (void)layoutSubviews { 

    CGSize labelSize = [self.labelDescription sizeThatFits:CGSizeMake(self.frame.size.width, FLT_MAX)]; 

    if (self.constraintHeight) { 
     [self removeConstraint:self.constraintHeight]; 
    } 

    self.constraintHeight = [NSLayoutConstraint constraintWithItem:self.labelDescription attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0 constant:labelSize.height]; 

    [self addConstraint:self.constraintHeight]; 

    [super layoutSubviews]; 
} 

nie Gdyby tak się stało automatycznie autoLayout?

EDIT

Struktura moim zdaniem jest:

UIScrollView 
---> UIView 
    ---> UILabel 

Oto ograniczenia dotyczące UIScrollView:

<NSLayoutConstraint:0x120c4860 H:|-(>=32)-[DescriptionView:0x85c81c0] (Names: '|':UIScrollView:0x85db650)>, 
<NSLayoutConstraint:0x120c48a0 H:|-([email protected])-[DescriptionView:0x85c81c0] priority:900 (Names: '|':UIScrollView:0x85db650)>, 
<NSLayoutConstraint:0x120c48e0 H:[DescriptionView:0x85c81c0(<=576)]>, 
<NSLayoutConstraint:0x120c4920 H:[DescriptionView:0x85c81c0]-(>=32)-| (Names: '|':UIScrollView:0x85db650)>, 
<NSLayoutConstraint:0x120c4960 H:[DescriptionView:0x85c81c0]-([email protected])-| priority:900 (Names: '|':UIScrollView:0x85db650)>, 
<NSLayoutConstraint:0x8301450 DescriptionView:0x85c81c0.centerX == UIScrollView:0x85db650.centerX>, 

Oto ograniczenia dotyczące UIView:

<NSLayoutConstraint:0x85c4580 V:|-(0)-[UILabel:0x85bc7b0] (Names: '|':DescriptionView:0x85c81c0)>, 
<NSLayoutConstraint:0x85c45c0 H:|-(0)-[UILabel:0x85bc7b0] (Names: '|':DescriptionView:0x85c81c0)>, 
<NSLayoutConstraint:0x85c9f80 UILabel:0x85bc7b0.trailing == DescriptionView:0x85c81c0.trailing>, 
<NSLayoutConstraint:0x85c9fc0 UILabel:0x85bc7b0.centerY == DescriptionView:0x85c81c0.centerY> 

Sam UILabel nie ma żadnych ograniczeń, poza przypinaniem go do krawędzi rodzica

+0

jakie są ograniczenia na etykiecie i pojemniku, w którym się znajduje? – larsacus

+0

Dodano ograniczenia do pierwotnego postu – simon

+0

Więc jedyne ograniczenia, które ustawiliście na etykiecie, to fakt, że wypełnia on kontener zarówno w poziomie, jak iw pionie? Czy tekst jest obcięty, gdy kontener ma określony rozmiar, czy też zawsze obcina tekst niezależnie od wielkości kontenera? – larsacus

Odpowiedz

26

Naprawiłem ten problem po zgłoszeniu błędu z Apple. Kwestia tego tekstu wielowierszowego wymaga podejścia dwa przejścia do układu i to wszystko opiera się na własności preferredMaxLayoutWidth

Oto odpowiedni kod, który należy dodać do kontrolera widoku, który zawiera etykietę wielowierszowego:

- (void)viewWillLayoutSubviews 
{ 
    // Clear the preferred max layout width in case the text of the label is a single line taking less width than what would be taken from the constraints of the left and right edges to the label's superview 
    [self.label setPreferredMaxLayoutWidth:0.]; 
} 

- (void)viewDidLayoutSubviews 
{ 
    // Now that you know what the constraints gave you for the label's width, use that for the preferredMaxLayoutWidth—so you get the correct height for the layout 
    [self.label setPreferredMaxLayoutWidth:[self.label bounds].size.width]; 

    // And then layout again with the label's correct height. 
    [self.view layoutSubviews]; 
} 
+1

Dzięki za udostępnienie tego rozwiązania - całkowicie nie do zniesienia! – matt

+3

Jednak testowałem to rozwiązanie i stwierdziłem, że ustawienie preferowanej etykietyMaxLayoutWidth wciąż jest za późno na jeden cykl układu. Czasami pasuje do tekstu, a czasem kilka ostatnich słów tekstu jest usuwanych z etykiety (nie jest wystarczająco wysoka). – matt

+0

zostało to naprawione na 6.1? – midas06

41

Dobra, w końcu to zrobiłem. Rozwiązaniem jest ustawienie preferredMaxLayoutWidth w viewDidLayoutSubviews, ale tylko po pierwszej rundzie układu. Możesz to ustawić, wysyłając asynchronicznie z powrotem do głównego wątku. Więc:

- (void)viewDidLayoutSubviews { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     self.theLabel.preferredMaxLayoutWidth = self.theLabel.bounds.size.width; 
    }); 
} 

W ten sposób, nie ustawić preferredMaxLayoutWidthpo szerokość etykiecie został prawidłowo ustawiony przez swoich ograniczeń związanych Superview-.

przykład praca projekt tutaj:

https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/ch23p673selfSizingLabel4/p565p579selfSizingLabel/ViewController.m

EDIT: Innym podejściem! Podklasą UILabel i zastąpić layoutSubviews:

- (void) layoutSubviews { 
    [super layoutSubviews]; 
    self.preferredMaxLayoutWidth = self.bounds.size.width; 
} 

Rezultatem jest samodzielnym doborze label - automatycznie zmienia swoją wysokość, aby pomieścić swoją zawartość bez względu na sposób jej zmiany szerokości (zakładając jego szerokość jest zmieniana przez ograniczenia/Układ).

+0

To działa dobrze. Dzięki! – lichen19853

+1

@ lichen19853 zauważ, że to rozwiązanie jest potrzebne tylko w dziwnej sytuacji OP, gdzie superview zmienia rozmiar i zmienia szerokość etykiety poprzez wiązania. Jeśli zmienisz szerokość etykiety bezpośrednio, np. poprzez zmianę ograniczenia szerokości w kodzie, możesz po prostu zmienić jego "preferredMaxLayoutWidth" tam i wtedy. – matt

+2

O ile mogę powiedzieć, to rozwiązanie nie działa, gdy widok nadrzędny ponownie się rozrasta - etykiety nie rozwijają się, aby zająć jakąkolwiek nową dostępną przestrzeń. – simon

4

W Xcode 6.1 na iOS 7/8 udało mi się uruchomić tę funkcję, ustawiając tylko preferredMaxLayoutWidth w metodzie ustawiającej, która jest wywoływana w moim widoku, aby wyświetlić tekst etykiety. Zgaduję, że został ustawiony na 0 na początek. Przykład poniżej, gdzie etykieta to self.teachPieceLabel.Etykieta jest połączona wiązaniami z innymi etykietami w widoku w programie Interface Builder.

- (void)setTeachPieceText:(NSString *)teachPieceText { 
     self.teachPieceLabel.text = teachPieceText; 
     [self.teachPieceLabel setPreferredMaxLayoutWidth:[self.teachPieceLabel bounds].size.width]; 
}