2013-05-30 11 views
39

Następujący kod (wywołany w viewDidLoad) powoduje, że ekran jest w pełni czerwony. Spodziewałbym się, że będzie to w pełni zielony ekran. Dlaczego jest czerwony? I jak mogę wszystko zmienić na zielone?Autouzupełnianie w iOS z UIScrollview: Dlaczego widok zawartości przewijania nie wypełnia widoku przewijania?

UIScrollView* scrollView = [UIScrollView new]; 
scrollView.translatesAutoresizingMaskIntoConstraints = NO; 
scrollView.backgroundColor = [UIColor redColor]; 
[self.view addSubview:scrollView]; 

UIView* contentView = [UIView new]; 
contentView.translatesAutoresizingMaskIntoConstraints = NO; 
contentView.backgroundColor = [UIColor greenColor]; 
[scrollView addSubview:contentView]; 

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView,contentView); 

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]]; 
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]]; 

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]]; 
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]]; 

Odpowiedz

66

Ograniczenia z widokami przewijania działają nieco inaczej niż w przypadku innych widoków. Ograniczenia między contentView i superview (scrollView) są scrollView 's contentSize, a nie jego frame. To może wydawać się kłopotliwe, ale w rzeczywistości jest całkiem przydatne, co oznacza, że ​​nigdy nie musisz dopasowywać contentSize, ale raczej contentSize automatycznie dostosuje się do twoich treści. To zachowanie jest opisane w Technical Note TN2154.

Jeśli chcesz zdefiniować rozmiar contentView na ekranie lub coś podobnego, musisz dodać ograniczenie między contentView a widokiem głównym, na przykład. Jest to, wprawdzie, sprzeczne z treścią przewijania, więc pewnie bym tego nie poradził, ale można to zrobić.


Aby zilustrować tę koncepcję, że wielkość contentView będzie napędzany przez jego zawartości, a nie przez bounds na scrollView, dodać etykietę do contentView:

UIScrollView* scrollView = [UIScrollView new]; 
scrollView.translatesAutoresizingMaskIntoConstraints = NO; 
scrollView.backgroundColor = [UIColor redColor]; 
[self.view addSubview:scrollView]; 

UIView* contentView = [UIView new]; 
contentView.translatesAutoresizingMaskIntoConstraints = NO; 
contentView.backgroundColor = [UIColor greenColor]; 
[scrollView addSubview:contentView]; 

UILabel *randomLabel = [[UILabel alloc] init]; 
randomLabel.text = @"this is a test"; 
randomLabel.translatesAutoresizingMaskIntoConstraints = NO; 
randomLabel.backgroundColor = [UIColor clearColor]; 
[contentView addSubview:randomLabel]; 

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel); 

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|" options:0 metrics:0 views:viewDict]]; 
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|" options:0 metrics:0 views:viewDict]]; 

[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[contentView]|" options:0 metrics:0 views:viewDict]]; 
[scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[contentView]|" options:0 metrics:0 views:viewDict]]; 

[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]]; 
[contentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[randomLabel]-|" options:0 metrics:0 views:viewDict]]; 

Teraz będziesz zobacz, że contentView (i, w związku z tym, contentSize z scrollView) są dostosowane tak, aby pasowały do ​​etykiety ze standardowymi marginesami. A ponieważ nie określiłem szerokości/wysokości etykiety, która zostanie dostosowana w oparciu o tekst, który umieścisz w tej etykiecie.


Jeśli chcesz contentView również dostosować do szerokości widoku głównym, można zrobić przedefiniować swoją viewDict jak tak, a następnie dodać te dodatkowe ograniczenia (w dodatku do wszystkich innych, wyżej):

UIView *mainView = self.view; 

NSDictionary* viewDict = NSDictionaryOfVariableBindings(scrollView, contentView, randomLabel, mainView); 

[mainView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[contentView(==mainView)]" options:0 metrics:0 views:viewDict]]; 

jest known issue (bug?) z multilinii etykiet w scrollviews, że jeśli chcesz go zmienić rozmiar w zależności od ilości tekstu, trzeba zrobić kilka kuglarstwo, takich jak:

dispatch_async(dispatch_get_main_queue(), ^{ 
    randomLabel.preferredMaxLayoutWidth = self.view.bounds.size.width; 
}); 
+1

I nie wydają się uzyskać etykietę, aby poszerzyć pionowo, jeśli tekst jest zbyt długi, aby zmieścić się na jedna linia. Ustawiłem liczbę linii na 0, a lineBreakMode na NSLineBreakByWordWrapping. Czy czegoś brakuje? – rdelmar

+0

Dodatkowo, dodałem ostatnią linię w twojej odpowiedzi, aby przypiąć szerokość contentView do szerokości ekranu (w przeciwnym razie szerokość contentView jest wystarczająco szeroka, aby pomieścić długi tekst). Jeśli wyraźnie ustawię wysokość etykiety z ograniczeniem wysokości, to działa. – rdelmar

+0

Tak, Matt odkrył [kilka obejść] (http://stackoverflow.com/questions/13149733/ios-autolayout-issue-with-uilabels-in-a-resizing-parent-view) dla tego wydania/błąd w etykietach wielowierszowych. Dodałem jeden z nich na samym dole mojej odpowiedzi. Całkowicie niezadowalające rozwiązanie. Wygląda na to, że musisz wybrać między wartościami hardcoding lub tym kludgy obejściem. – Rob

1

Próbowałem, aby odpowiedź Roba na pierwszy rzut oka wyglądała dobrze. ALE! jeśli włączyłeś także powiększając, ten kod Autolayout będzie przeszkadzał. Zmienia rozmiar treści podczas powiększania. Oznacza to, że po powiększeniu (zoomScale> 1) nie będę w stanie przewijać części poza ekranem.

Po wielu dniach walki z Autolayout, nie mogłem znaleźć żadnego rozwiązania. W końcu to nawet nie ma znaczenia (ok, przepraszam). W końcu, po prostu usunę Autolayout na contentView (użyj fixed contentViewView), a następnie w layoutSubviews, dostosowujęself.scrollView.contentInset. (Używam Xcode5, iOS 7)

Wiem, że to nie jest bezpośrednie rozwiązanie tego pytania. Ale chcę tylko wskazać proste obejście.Działa idealnie do centrowania zawartości o stałym rozmiarze ViewView w scrollView, z zaledwie 2 liniami kodu! Nadzieję, że może to komuś pomóc;)

- (void)layoutSubviews { 
    [super layoutSubviews]; 

    // move contentView to center of scrollView by changing contentInset, 
    // because I CANNOT set this with AUTOLAYOUT!!! 
    CGFloat topInset = (self.frame.size.height - self.contentView.frame.size.height)/2; 
    self.scrollView.contentInset = UIEdgeInsetsMake(topInset, 0, 0, 0); 
} 
-1

Ogólnie Auto Układ uważa, górny, dolny, lewy, i prawy brzeg aby być widoczne krawędzie. Oznacza to, że jeśli przypniesz widok do lewej krawędzi jego podglądu, naprawdę przypniesz go do minimalnej wartości x granic superwizji. Zmiana początku związku z podglądem nie zmienia pozycji widoku.

Klasa UIScrollView przewija zawartość, zmieniając początek jej granic. Aby to działało z Auto Layout, górna, lewa, dolna i prawa krawędź w widoku przewijania oznaczają teraz krawędzie jego widoku zawartości.

Ograniczenia na podstronach widoku przewijania muszą dawać rozmiar do wypełnienia, który jest następnie interpretowany jako rozmiar zawartości widoku przewijania. (Nie należy tego mylić z metodą wewnętrznąContentSize używaną do automatycznego układania). Aby zmienić rozmiar ramki widoku przewijania za pomocą automatycznego układu, wiązania muszą być wyraźne w odniesieniu do szerokości i wysokości widoku przewijania lub krawędzie widoku przewijania muszą być związane z widokami poza jego poddrzewem.

Należy zauważyć, że widok podrzędny widoku przewijania wydaje się unoszący się (nie przewijać) nad pozostałą przewijaną treścią, tworząc wiązania między widokiem a widokiem poza poddrzewanym obszarem przeglądanym, takim jak widok przeglądania przewijania.

Oto dwa przykłady jak skonfigurować widok przewijania, pierwsze podejście mieszane, a następnie czystą podejście

+0

Witamy w przepełnieniu stosu. Zapoznaj się z [Jak napisać dobrą odpowiedź] (https://meta.stackexchange.com/questions/7656/how-do-i-write-a-good-answer-to-a-question). – Rick