Jak mogę użyć Autolayout, aby ustawić ograniczenia w moim UIScrollview?


176

Spędziłem dwa dni na wypróbowywaniu różnych rozwiązań dla podejść Mixed i Pure Autolayout, aby osiągnąć coś, co było trywialną konfiguracją widoku przewijania przed automatycznym układem, a teraz jest to oficjalne - muszę być zbyt głupi. Ustawiam to głównie w Storyboard (cóż, tak po prostu jest).

Oto moja prośba o pomoc.

Viewtree:

UIView
-UIView
-UIView
..-UIScrollview
...-UIButton
...-UIButton
...-UIButton

Przyciski mają przewijać się w poziomie (od lewej do prawej i odwrotnie). Może ktoś proszę dać mi znać, jak ustawić ograniczenia do osiągnięcia tego przy użyciu czystego autoLayout ???

-

Wypróbowałem podejście mieszane, takie jak:

UIView
- UIView
- UIView
..-UIScrollview
...-UIView (contentview)
....-UIButton
....-UIButton
....-UIButton

... ograniczenia i ustawienie stałej szerokości i wysokości dla osób contentviewi translatesAutoresizingMaskIntoConstraintsustawienia, jak na Apple TechNote. Przyciski i widok przewijania są konfigurowane przy użyciu ograniczeń. Powoduje to przewijanie widoku scrollview (yay), ale niestety przewija się za daleko! O ile wiem, szerokość przewijania jest w jakiś sposób podwojona w stosunku do tego, co ustawiłem dla widoku treści na ??? !!! ???

Wypróbowałem również podejście w pełni autoukładane, zarówno z, jak contentviewi bez. Wszystkie widoki translatesAutoresizingMaskIntoConstraints=NOoprócz self.view. Przyciski mają stałe ograniczenia szerokości / wysokości i są przypięte do wszystkich czterech krawędzi widoku przewijania. Nic się nie przewija.

Jestem więc całkowicie zaskoczony, dlaczego nie mogę sprawić, by działał poprawnie. Każda pomoc jest mile widziana, a jeśli potrzebujesz dodatkowych informacji, zapytaj!

ZAKTUALIZOWANY Zrzut ekranu z rozwiązaniem - ograniczenia buttonZ:

wprowadź opis obrazu tutaj

EDYCJA @ Jamie Forrest Okazuje się, że rozwiązaniem jest błędne ograniczenie końcowe na ostatnim przycisku. Zamiast 6441 wartość, którą ustawiłem, była ujemna, -6441. Trudność polega na tym, że podczas ustawiania wartości w scenorysie na pasku narzędzi Pin dostępne są dwie opcje:

wprowadź opis obrazu tutaj

Bieżąca wartość kanwy jest ujemna (co prowadzi do braku przewijania), a poniższa opcja jest dodatnia (aktywacja przewijania). To znaczy, że nie jestem głupi, ale przynajmniej na wpół ślepy. Chociaż, na moją obronę, czy nie jest trochę niepokojące, że XCode nie wyświetla błędu dla „nieprawidłowego” ustawienia?

EDITED PONOWNIE Teraz to zabawne ... zmiana wartości końcowej z -6441 (bez przewijania) na 6441 z włączonym przewijaniem. Ale mój stary przyjaciel powrócił „zbyt duży rozmiar treści”, co spowodowało, że rozmiar treści był dwa razy większy niż powinien! Rozwiązaniem umożliwiającym uzyskanie prawidłowego przewijania zawartości było ustawienie końcowego ograniczenia na ZERO! Nie jest to oczywiste podczas pracy w Storyboard, ale patrząc na kod @Infinity James, tak powinno być.


Gdzie obliczasz / ustawiasz rozmiar treści dla widoku przewijania? Odnosząc się do Twojej pierwszej próby użycia contentView i powiedziałeś, że przewija się za daleko.
Tim

2
O ile mi wiadomo, nie można ustawić contentSizesię z UIScrollViewużyciem tylko układ auto. I to contentSizeokreśla, ile możesz przewijać. Więc w końcu będziesz musiał to ustawić ręcznie. W pozostałej części można użyć ograniczeń układu, aby ustawić ramki widoku względem siebie.
Guillaume

@Jeff, rozmiar zawartości jest stały, nigdy się nie zmienia. Ustawiam rozmiar zawartości w serii ujęć, wprowadzając ręcznie prawidłową wysokość i szerokość dla widoku contentiview i przypinam wysokość i szerokość z ograniczeniami w serii ujęć.
user1459524

Wydrukuj swój contentSize w czasie wykonywania, sprawdź, czy pasuje do wprowadzonych wartości. ContentSize określa, ile występuje przewijanie, więc problem z pierwszą próbą dotyczy contentSize.
Tim

@Guillaume, więc podejście „czystego układu automatycznego” wcale nie jest takie czyste? Ale JAK ręcznie ustawić contentSize? Jak wspomniałem powyżej, ustawiam wysokość / szerokość widoku treści na stałe wartości (w scenorysie). Ale przewija się za daleko (2x).
user1459524

Odpowiedzi:


68

Trudno jest zobaczyć dokładne wartości i konfigurację ograniczeń, ponieważ wkleiłeś je tutaj, więc nie jestem pewien, czy spojrzeć na zrzuty ekranu, w których popełniłeś błąd.

Zamiast wyjaśnienia, co jest nie tak w twojej konfiguracji, stworzyłem podstawowy przykładowy projekt z bardzo podobną hierarchią widoków i ustawieniami ograniczeń do tego, który opisałeś. Przewijanie w poziomie działa zgodnie z oczekiwaniami w przykładowym projekcie, w którym zastosowano podejście „Pure AutoLayout” opisane przez firmę Apple w Uwadze technicznej .

Miałem też wiele problemów z początkowym uruchomieniem funkcji Auto Layout UIScrollView. Kluczem do jego działania jest upewnienie się, że wszystkie elementy w widoku przewijania, wzięte razem, mają ograniczenia, które ostatecznie łączą się ze wszystkimi stronami widoku przewijania i które przyczyniają się do tego, że system AutoLayout może określić rozmiar contentSize dla przewiń widok, który będzie większy niż jego ramka. Wygląda na to, że próbujesz to zrobić w swoim kodzie, ale być może miałeś tam jakieś zbędne ograniczenia, które sprawiały, że rozmiar contentSize był zbyt mały.

Warto również zauważyć, jak wspominali inni, w przypadku AutoLayout i UIScrollview nie ustawia się już jawnie parametru contentSize. System AutoLayout oblicza contentSize na podstawie twoich ograniczeń.

Uważam również, że ten rozdział ebook jest bardzo pomocny w zrozumieniu, jak to wszystko działa. Mam nadzieję, że to wszystko pomoże.


2
DZIĘKUJEMY za przykładowy projekt! Działa, a przeglądając go, na początku nie mogłem znaleźć żadnej różnicy w moim projekcie! Skopiowałem widoki do swojego projektu, podejrzewając inne ustawienia niż ograniczenia, ale to nadal działało. To sprawiło, że zauważyłem, że końcowe ograniczenie dla ostatniego przycisku w moim projekcie ma wartość ujemną - przed nim, podczas gdy twój ma wartość dodatnią! Zmiana - na pozytywne włączała przewijanie! Kiedy wyświetlam pasek narzędzi Pin, są dwie możliwości: Użyj bieżącej wartości kanwy, która jest ujemna, i widoku przewijania (użyj bieżącej wartości), która jest dodatnia ...?!
user1459524

O tak. Ujemna wartość faktycznie zmniejszyłaby contentSize widoku przewijania, aby dopasować się do faktu, że końcowa krawędź powinna kończyć się przed zakończeniem przycisku. Cieszę się, że przykładowy projekt pomógł!
Jamie Forrest

Zrobił dużo. Sprawdź moją zaktualizowaną odpowiedź. Wygląda na to, że końcowa wartość powinna wynosić 0 (zero).
user1459524

6
To smutne, że musimy udostępniać zrzuty ekranu zamiast kodu. Dzieje się tak tylko dlatego, że firma Apple zachęca programistów do korzystania z kreatora zamiast oferowania lepszego interfejsu API.
Vladimír Slavík

4
Całkowicie nieintuicyjny. Deweloperzy muszą marnować wiele godzin, aby dowiedzieć się, co działo się w umyśle twórców XCode.
Josh

49

LOL, witamy w klubie głupoty. Jestem jednym z założycieli. :RE

W przypadku przewijania VERTICAL : jedynym sposobem, w jaki mogłem go uruchomić (iOS 8, Xcode 6 i czysty autolayout), było dodanie następujących ograniczeń do mojego widoku przewijania (wszystkie związane z nadzorem):

  • Równe szerokości
  • Równe wysokości
  • Wyrównanie Y do środka
  • Wyrównanie X do środka

Moja struktura:

  UIView
   - ScrollView
    - Subview
    - Subview
    - Subview
    - Subview
    - ...

Oto wynik końcowy:

Próbny

To jest konfiguracja:

Ustawiać Pełny ekran

A oto projekt .

Miejmy nadzieję, że to uchroni kogoś przed zaśnięciem o 5 rano. :RE


Wielkie dzięki za pomoc! W jaki sposób otrzymałeś widok podrzędny typu „widok podrzędny”? Patrzę na Twój projekt w Xcode 6.2 i nazywa te małe prostokąty „Widokiem podrzędnym” z jedynym ograniczeniem, że ma wysokość 63 pikseli.
Andrew K

1
Pozdrowienia! Ten „Widok podrzędny” to w rzeczywistości UIVIew. To tylko nazwa ... Możesz tam wpisać cokolwiek. Obejrzyj ten obrazek: cl.ly/image/291f1K2N0V3p Jeśli chodzi o temat ograniczeń, podglądy mają więcej niż tylko ograniczenie wysokości. Sprawdź całą listę ograniczeń dla tych widoków tutaj: cl.ly/image/3l061i123j2i
backslash-f

1
Nadal nie mogę uruchomić przewijania - zauważyłem, że widoki subviews są „wyszarzone” w Twoim projekcie. Po przeprowadzeniu pewnych badań wygląda na to, że używasz „klas wielkości”. Jak to wpływa na przewijanie? Czy istnieje sposób, aby przewijanie działało bez użycia tego?
Andrew K

Co więcej, jak sprawiłeś, że Twój nadzór jest o wiele dłuższy niż domyślna długość? Próbuję dodać przyciski, które pojawią się „pod zakładką” (lub poza ekranem), ale oczywiście nie mogę ich dodać do superviewu, jeśli nie mogę ich przeciągnąć i upuścić na superview, ponieważ nie jest wystarczająco duży.
Andrew K

1
po długim dniu poszukiwań i prób wykonania tego głupiego układu, znalazłem tę odpowiedź i działa za pierwszym podejściem .. Dzięki stary .. ratujesz mój dzień .. chciałbym oddać tysiące głosów na tę odpowiedź ..: )
Bobby Stenly

32

Prosty samodzielny przykład

Sądząc po dużej liczbie głosów na pytanie i małej liczbie głosów na odpowiedzi, ludzie nie znajdują tutaj zrozumiałego i szybkiego rozwiązania. Spróbuję dodać jeden. Ten projekt jest samodzielnym przykładem wykonanym w całości w programie Interface Builder. Powinieneś być w stanie przepracować to w 10 minut lub mniej. Następnie możesz zastosować poznane koncepcje do własnego projektu.

wprowadź opis obrazu tutaj

Oryginalne pytanie dotyczy przycisków przewijania. Tutaj używam po prostu UIViews, ale mogą one reprezentować dowolny pogląd. Wybrałem również przewijanie w poziomie, ponieważ zrzuty ekranu scenorysu są bardziej kompaktowe dla tego formatu. Zasady są jednak takie same w przypadku przewijania w pionie.

Kluczowe idee

  • UIScrollViewPowinny używać tylko jeden podrzędny. To jest „UIView”, który służy jako widok zawartości do przechowywania wszystkiego, co chcesz przewinąć.
  • Ustaw widok zawartości i element nadrzędny widoku przewijania na równych wysokościach do przewijania w poziomie. (Równe szerokości przy przewijaniu w pionie)
  • Upewnij się, że cała przewijalna zawartość ma określoną szerokość i jest przypięta ze wszystkich stron.

Rozpocznij nowy projekt

Może to być tylko jedna aplikacja widoku.

Storyboard

W tym przykładzie stworzymy poziomy widok przewijania. Wybierz kontroler widoku, a następnie wybierz opcję Dowolny w Inspektorze rozmiaru. Zrób szerokość 1,000i wysokość 300. To po prostu daje nam miejsce w scenorysie, aby dodać zawartość, która będzie się przewijała.

wprowadź opis obrazu tutaj

Dodaj widok przewijania

Dodaj a UIScrollViewi przypnij wszystkie cztery boki do widoku głównego kontrolera widoku.

wprowadź opis obrazu tutaj

Dodaj widok zawartości

Dodaj UIViewjako widok podrzędny do widoku przewijania. To jest kluczowe. Nie próbuj dodawać wielu podglądów podrzędnych do widoku przewijania. Po prostu dodaj jeden UIView. To będzie widok zawartości dla innych widoków, które chcesz przewijać. Przypnij widok zawartości do widoku przewijania ze wszystkich czterech stron.

wprowadź opis obrazu tutaj

Równe wysokości

Teraz w konspekcie dokumentu Commandkliknij zarówno widok zawartości, jak i widok nadrzędny widoku przewijania , aby zaznaczyć oba. Następnie ustaw równe wysokości ( Controlprzeciągnij z widoku zawartości do widoku przewijania). To też jest kluczowe. Ponieważ przewijamy poziomo, widok zawartości widoku przewijania nie będzie wiedział, jak wysoko powinien być, chyba że ustawimy go w ten sposób.

wprowadź opis obrazu tutaj

Uwaga:

  • Gdybyśmy przewijali zawartość w pionie, ustawilibyśmy szerokość widoku zawartości na równą szerokości elementu nadrzędnego widoku przewijania.

Dodaj zawartość

Dodaj trzy UIViewi daj im wszystkie ograniczenia. Do wszystkiego użyłem 8-punktowego marginesu.

wprowadź opis obrazu tutaj

Ograniczenia:

  • Widok zielony: przypnij górną, lewą i dolną krawędź. Zrób szerokość 400.
  • Widok czerwony: przypnij górną, lewą i dolną krawędź. Zrób szerokość 300.
  • Widok fioletowy: przypnij wszystkie cztery krawędzie krawędzi. Ustaw szerokość niezależnie od pozostałej przestrzeni (w tym przypadku 268).

Kluczowe jest również ustawienie ograniczeń szerokości, aby widok przewijania wiedział, jak szeroki będzie widok zawartości.

Skończone

To wszystko. Możesz teraz uruchomić swój projekt. Powinien zachowywać się jak przewijany obraz u góry tej odpowiedzi.

W przypadku przewijania w pionie po prostu zamień wszystkie kierunki szerokości i wysokości w tym przykładzie (przetestowane i działające).

Dalsze badanie


9

ContentSize jest niejawnie ustawiana przez zastosowanie ograniczeń wewnątrz UIScrollView.

Na przykład, jeśli masz UIScrollView wewnątrz UIView, będzie to wyglądać tak (jak jestem pewien, że wiesz):

    UIView *containerView               = [[UIView alloc] init];
    UIScrollView *scrollView            = [[UIScrollView alloc] init];
    [containerView addSubview:scrollView];
    containerView.translatesAutoresizingMaskIntoConstraints = NO;
    scrollView.translatesAutoresizingMaskIntoConstraints    = NO;
    NSDictionary *viewsDictionary       = NSDictionaryOfVariableBindings(containerView, scrollView);

    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil
                                                                            views:viewsDictionary]];
    [containerView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[scrollView]|"
                                                                          options:kNilOptions
                                                                          metrics:nil

Spowoduje to ustawienie scrollView na wypełnienie rozmiaru containerView (tak więc containerView będzie musiał mieć określony rozmiar).

Następnie możesz dostosować contentSize UIScrollView, niejawnie ustawiając go tak, aby był wystarczająco duży, aby pomieścić przyciski w następujący sposób:

    UIButton *buttonA                   = [[UIButton alloc] init];
    UIButton *buttonB                   = [[UIButton alloc] init];
    UIButton *buttonC                   = [[UIButton alloc] init];
    [scrollView addSubview:buttonA];
    [scrollView addSubview:buttonB];
    [scrollView addSubview:buttonC];
    buttonA.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonB.translatesAutoresizingMaskIntoConstraints       = NO;
    buttonC.translatesAutoresizingMaskIntoConstraints       = NO;

    viewsDictionary                     = NSDictionaryOfVariableBindings(scrollView, buttonA, buttonB, buttonC);

    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[buttonA]-|"
                                                                       options:kNilOptions
                                                                       metrics:nil
                                                                         views:viewsDictionary]];
    [scrollView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[buttonA]-[buttonB]-[buttonC]-|"
                                                                       options:NSLayoutFormatAlignAllBaseline
                                                                       metrics:nil
                                                                         views:viewsDictionary]];

Więc ustawiam ograniczenia między scrollView a przyciskami, a nie containerView i przyciskami? Myślę, że to jedyna różnica, jaką widzę między twoim kodem a tym, co teraz robię za pomocą scenorysu.
user1459524

Dopiero po drugim czytaniu zdałem sobie sprawę, że konfigurujesz widok CONTAINERview, a nie CONTENTview. Na podstawie twojego kodu odtworzyłem wszystko dokładnie w scenorysie i nie przewija się. Zmienię moje pytanie za pomocą kilku zrzutów ekranu.
user1459524

1
Okazuje się, że moja próba odtworzenia kodu w scenorysie nie była w 100% poprawna. Wartość końcowa ostatniego przycisku powinna wynosić dokładnie zero, odzwierciedlając H: | - [buttonA] - [buttonB] - [buttonC] - | co nie jest zbyt oczywiste podczas pracy w storyboardzie (a przynajmniej nie było dla mnie), ale teraz wydaje się to trywialne. Uwielbiam układy automatyczne, ale te małe rzeczy cię
łapią

To, o czym wspomniał @ user1459524, było dla mnie problemem. Moim dolnym widokiem był przycisk, a dolnym ograniczeniem było -32 przez IB. Ustawiłem to na 0 i zaktualizowałem w IB na Bottom Space na: superview. To zadziała, również wydaje się, że tak długo, jak długo jesteś po pozytywnej stronie, działa. Wygląda na to, że może to być błąd w IB. Mam nadzieję, że to pomoże komuś innemu. Usunąłem również wszystkie widoki i ponownie okablowałem, co pomaga podczas próby ich rozmieszczenia i zwykle nie zajmuje to dużo czasu.
Michael

8

Jest tak wiele pytań dotyczących używania AutoLayout z UIScrollView, kluczową kwestią, którą ignorujemy, jest to, że wewnętrzne widoki UIScrollView tworzą ograniczenia względem widoku zawartości, ale nie samego UIScrollView. Zapoznaj się z uwagą techniczną TN2154 , w której można znaleźć:

Klasa UIScrollView przewija swoją zawartość, zmieniając pochodzenie granic. Aby to działało z automatycznym układem, górna, lewa, dolna i prawa krawędź w widoku przewijania oznaczają teraz krawędzie jego widoku zawartości.

Poniższy rysunek przedstawia, że: wprowadź opis obrazu tutaj

Możesz znaleźć końcową spację to 500 punktów, jeśli ograniczenie zostanie nałożone na UIScrollView, widok zostanie pominięty i należy zaktualizować jego ramkę. Jednak żadnych ostrzeżeń i błędów. Ponieważ wszystkie ograniczenia dotyczą widoku zawartości.

UIScrollView obliczy rozmiar widoku zawartości zgodnie z ograniczeniami widoków wewnętrznych. (Na przykład rozmiar zawartości: szerokość = 100 (spacja wiodąca) + 200 (szerokość widoku) + 500 (spacja na końcu), wysokość = 131 (odstęp na górze) + 200 (wysokość) + 269 (odstępy na dole)

Jak dodać ograniczenia dla widoków w UIScrollView:

  1. Obrazowanie pozycji widoków w widoku treści.
  2. Dodaj odstępy górny, prawy, dolny, lewy na krawędziach widoku zawartości, a ponadto szerokość i wysokość tych widoków.

I wszystko to jest zrobione.

Łatwym sposobem radzenia sobie z autoukładem w widoku przewijania jest dodanie widoku kontenera zawierającego wszystkie podglądy w widoku przewijania.

Wniosek: kluczową kwestią do zrozumienia AutoLayout z UIScrollView jest to, że widoki wewnętrzne tworzą ograniczenia względem widoku zawartości, ale nie samego UIScrollView.

załączony przykładowy kod


5

Poniższe rozwiązanie zadziałało dla mnie dla scrollView z autolayout i bez contentSize :

  1. Przeciągnij i upuść scrollView do viewController i zastosuj dowolne ograniczenia, aby objąć żądaną przestrzeń.
  2. Przeciągnij n upuść UIView wewnątrz scrollView i spraw, aby obejmował całą przestrzeń scrollView i zastosuj ograniczenia, aby były górne, lewe, prawe i dolne z scrollView.
  3. Ustaw wysokość (i szerokość, jeśli wymagane jest przewijanie w poziomie) widoku wewnętrznego zgodnie z potrzebą przewijania. W razie potrzeby tę część można również wykonać z kodu.
  4. Krytyczne . Po ustawieniu wysokości na jakąś dużą wartość w punkcie (3), wróć do punktu (2) i upewnij się, że ustawiłeś górną, lewą, prawą i dolną wartość z powrotem na zero, ponieważ Xcode mógł je zmienić, gdy wymuszasz zmieniono wysokość w (3).

I jesteś skończony. Teraz możesz dodać dowolną liczbę kontrolek w tym widoku i zastosować ograniczenia powiązane ze sobą (które nie działają bez tego widoku). Jeśli nie chcesz używać tego widoku, musisz zastosować ograniczenia dla każdej kontrolki związanej z scrollView (niezwiązanej ze sobą).


Przytłaczająca wskazówka ..............

Krytyczne . Powiedzmy dla jasności, że UIScrollView ma szerokość 1000 i wysokość 100. (W rzeczywistości normalnie te wartości byłyby oczywiście dynamiczne, w zależności od szerokości urządzenia itp. Ale na razie powiedzmy, że szerokość 1000 i wysokość 100). Powiedzmy, że wykonujesz przewijanie w poziomie. Więc umieść UIView wewnątrz UIScrollView. (To jest „widok treści”.) Ustaw wszystkie cztery ograniczenia widoku zawartości od góry, dołu, wiodące i końcowe, do widoku przewijania. Wyzeruj je wszystkie, nawet jeśli wydaje się to niewłaściwe. Ustaw wysokość zawartości UIView na 100 i zapomnij o tym. Teraz: chcesz przewijać w poziomie, więc ustaw szerokość widoku zawartości na powiedzmy 1225.

Zauważ, że szerokość widoku zawartości jest teraz 225 większa niż szerokość nadrzędnego widoku przewijania. To jest OK: w rzeczywistości MUSISZ to zrobić. Zauważ, że

... NIE ustawiasz końcowej szerokości na minus 225 ...

można by pomyśleć, że należy „dopasować” szerokości w normalny sposób . Ale jeśli to zrobisz, to w ogóle nie zadziała.

Musisz ustawić początkowe i końcowe liczby na ZERO , nigdy ujemne (nawet jeśli szerokość jest „większa”)

Co ciekawe, w rzeczywistości możesz ustawić początkowe / końcowe liczby na dowolną wartość dodatnią (powiedz „50”), co daje pewien margines odbicia. (Często wygląda świetnie: spróbuj.) Każda wartość ujemna na jednym z końców „cicho się załamie”.

Zauważ, że irytująco często Xcode (w każdym razie od 7.3.1),

„pożytecznie” ustawi te wartości na liczby ujemne!

ponieważ próbuje automatycznie je policzyć. Jeśli tak, po cichu pęknie. W pierwszej kolejności ustaw wszystkie cztery wartości na zero. I ustaw szerokość widoku zawartości na znacznie szerszą niż „1000” w przykładzie.


Edytowane: skończyło się na użyciu UITableView zamiast UIScrollView dla większości moich wymagań. Ponieważ tableView wydaje mi się znacznie bardziej elastyczny i dynamiczny.


To właściwie najlepsza odpowiedź. Dzięki!
Fattie

4

Zakładam, że masz problemy z contentSize. Zapoznaj się z tym postem na blogu, aby dowiedzieć się, jak radzić sobie z contentSize„czystym” podejściem do automatycznego układu. Istota tego polega na tym, że ograniczenia niejawnie definiują rozmiar zawartości. NIGDY nie ustawiasz go jawnie podczas korzystania z AutoLayout. Na końcu wpisu na blogu załączyłem przykładowy projekt, aby zademonstrować, jak to działa


3

W notatkach technicznych jest fragment, który być może przejrzałeś. Możesz niejawnie ustawić rozmiar zawartości widoku przewijania, używając ograniczeń ustalonych na krawędziach widoku przewijania.

Oto prosty przykład. Utwórz scenorys z jednym widokiem, który ma jeden widok przewijania. Ustaw ograniczenia widoków przewijania, aby dopasować je do rozmiaru widoku, w którym go umieściłeś.

Wewnątrz tego widoku przewijania dodaj pojedynczy widok. Jawnie ustaw rozmiar tego widoku za pomocą ograniczeń (i upewnij się, że rozmiar jest większy niż widok przewijania).

Teraz dodaj cztery dodatkowe wiązania do tego widoku wewnętrznego, blokując cztery krawędzie widoku wewnętrznego z jego nadrzędnym widokiem przewijania. Te cztery ograniczenia spowodują rozszerzenie rozmiaru zawartości, aby pomieścić widok wewnętrzny.

Jeśli masz wiele widoków, które chcesz dodać do widoku przewijania, na przykład ułożonych poziomo, możesz zablokować lewą stronę pierwszego widoku podrzędnego po lewej stronie widoku przewijania, zablokować podglądy względem siebie w poziomie, a prawą ostatniego widoku podrzędnego po prawej stronie widoku przewijania. Te ograniczenia zmusiłyby rozmiar zawartości widoku przewijania do rozszerzenia, aby pomieścić wszystkie podwidoki i ich ograniczenia.


3

Jeśli Twoje pytanie brzmi „Jak umieścić kilka UITextField w przewijanym w pionie UIScrollView, tak aby znikały one z klawiatury, gdy są aktywne”, najlepszą odpowiedzią jest:

Nie.

Zamiast tego użyj UITableViewController z komórkami statycznymi.

Otrzymujesz to zachowanie przewijania za darmo, ORAZ wszystkie wstawki zawartości Just Work, jeśli kontroler widoku jest wyświetlany wewnątrz UINavigationController.


3

Powinieneś zorganizować układ w ten sposób, że
ViewControllerViewzawiera ScrollView, ScrollViewzawiera ContainerView, ContainerViewzawiera 2Labels
wprowadź opis obrazu tutaj

Następnie wykonaj 3 kroki, aby ScrollViewprzewijać puszkę

  1. Ustawiam ScrollViewpin (górny / prawy / dolny / lewy) naViewControllerView
    • Ustawiam ContainerViewpin (górny / prawy / dolny / lewy) naScrollView
    • Ustaw Horizontally in Container( nie ustawiaj Vertically in Container)
    • Label1przypnij ( góra / prawo / lewo) doContainerView
    • Label1przypnij (prawy / lewy / dolny ) do ContainerViewi górny doLabel1

wprowadź opis obrazu tutaj

TUTAJ jest projekt demo

Mam nadzieję, że to pomoże


1

Podejście w pełni autoukład działa pięknie, ale konfiguracja jest dość uciążliwa, jeśli migrujesz z innego układu. Zrobiłem to już kilka razy i mam kilka ogólnych wskazówek:

  • Zacznij od małego: nawet jeśli oznacza to odtworzenie widoków scenorysu, zacznij od zaledwie kilku elementów i powoli buduj widoki, upewniając się, że po dodaniu kilku elementów sprawdza się, czy przewijanie działa.
  • Wyłącz translatesAutoresizingMaskIntoConstraints na wszystkim: to zawsze było przyczyną konfliktów ograniczeń.
  • Ustaw poprawnie swoje ograniczenia UIScrollView: upewnij się, że widok przewijania jest połączony ze wszystkich stron z widokiem nadrzędnym, w przeciwnym razie po prostu się nie rozwinie.

1

Po pewnym czasie uporania się z tym problemem w końcu znalazłem rozwiązanie. Pracuję z storyboardami o uniwersalnych rozmiarach klasowych (600x600). Utworzyłem UIView (contentView) rozmiar scrollView i utworzyłem ograniczenia do Top, Bottom, Leading i Trailing do scrollView. Następnie ręcznie przyciąłem rozmiar contentView do 600x600. Storyboard przestał próbować zmieniać rozmiar wszystkiego i mogłem pracować, ale widok wyglądał okropnie na prawdziwym urządzeniu lub symulatorze. Zrobiłem 2 wyloty ograniczające o tych obciętych rozmiarach.

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewWidthConstraint; 
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *contentViewHeightConstraint;

Następnie w viewDidLoad

CGSize viewSize = self.view.frame.size;
self.contentViewWidthConstraint.constant = viewSize.width;
self.contentViewHeightConstraint.constant = viewSize.height;

Działa świetnie.


1

Spędziłem dni próbując znaleźć rozwiązanie, jak korzystać z widoku AutoLayout i osadzonego widoku Scrollview, aby wyśrodkować widok przewijania na widocznym ekranie, który działa na wszystkich urządzeniach / wymiarach ekranu, a także przy obracaniu ekranu.

Spędziłem dni, próbując zrobić to tylko z Autolayout, i zbliżyłem się, ale nigdy wystarczająco blisko. Więc w końcu musiałem dodać 3 linie kodu również na ekran, w viewDidLoad.

Zobacz rozwiązanie poniżej:

  1. Utwórz widok przewijania i wypełnij go dowolnymi obiektami
  2. Włącz układ automatyczny
  3. Następnie wyśrodkuj ScrollView w pionie i poziomie Center ScrollView
  4. Wybierz Widok, a następnie „Dodaj brakujące ograniczenia” - to robi swoje
  5. W rezultacie generowanych jest wiele ograniczeń. Dla widoku utworzono 2 nowe widoki: „Widok z przestrzeni poziomej do widoku” i „Widok przewijania w przestrzeni pionowej, aby wyświetlić” lub odwrotnie.
  6. Usuń widok przewijania przestrzeni poziomej do widoku, dzięki czemu masz teraz 3 ograniczenia w widoku. 2 do wprowadzania widoku przewijania w widoku i do ustawiania odstępu w pionie między widokiem przewijania a widokiem
  7. Teraz połącz ograniczenie Vert ze swoim kodem, klikając i Ctrl przeciągając je do pliku nagłówkowego i tworząc IBOutlet NSLayoutConstraint (nazwałem moje ograniczenieVertVtoSV)
  8. Teraz przejdź do pliku .m i dodaj te wiersze kodu do viewDidLoad (graj z dopełnieniem, aby uzyskać prawidłowe wyśrodkowanie w pionie)

    if (IPAD)

    {self.constraintVertVtoSV.constant = 150,0; }

  9. powinno to teraz działać na wszystkich urządzeniach i być odpowiednio wyśrodkowane i nadal prawidłowo przewijać.


1

Jeśli tak jak ja po prostu używasz statycznej treści bez ograniczeń w podglądzie, na przykład możesz to zrobić:

override func viewDidLayoutSubviews() {
    scrollView.contentSize = CGSizeMake(320, 800)
}

1

Podobny problem mam dzisiaj z iOS 8.4, Xcode 6.4

Tam jest widok zawierający widok przewijania, zawierający contentView (UIView) zawierający podglądy.

Wszystko jest wszędzie w automatycznym układzie. Krawędzie widoku przewijania są przypięte do krawędzi widoków macierzystych za pomocą wiązań. Krawędzie widoku zawartości są przypięte do krawędzi widoku przewijania za pomocą ograniczeń.

Początkowo widok treści nie zmieniałby rozmiaru jako pełnej szerokości widoku przewijania. Musiałem dodać dodatkowe ograniczenie w widoku zawartości, aby jego szerokość była zgodna z nadrzędnym widokiem przewijania. Albo mogę ustawić ograniczenie contentView.centerX == scrollView.centerX. Każda z nich oprócz przypinania krawędzi nagle sprawiła, że ​​treść była wyświetlana prawidłowo.

// Either one of these additional constraints are required to get autolayout to correctly layout the contentView. Otherwise contentView size is its minimum required size
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: .CenterX, relatedBy: .Equal, toItem: scrollView, attribute: .CenterX, multiplier: 1.0, constant: 0))
scrollView.addConstraint(NSLayoutConstraint(item: contentView, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: scrollView, attribute: .Width, multiplier: 1.0, constant: 0.0))

Przypinanie krawędzi widoku treści do widoku scroll za pomocą wizualnych ograniczeń formularza,

let cvConstraints = ["H:|[contentView]|", "V:|[contentView]|"]

Używam procedury do iteracji po tablicy i dodania ich do scrollView.


1

Miałem podobny problem. Ustawiłem wszystkie ograniczone i zawsze zastanawiałem się, dlaczego nadal zmienia rozmiar niektórych podwidoków. Moim rozwiązaniem było ustawienie clipsToBounds na YES.


1

W szybkich można użyć tego roztworu roboczego.

Ograniczenia

ScrollView: Wiodący, kończący, górny, dolny = nadzór

ContentView: Leading, Trailing, Top, Bottom = ScrollView. Wysokość stała / w stosunku do zawartości.

Możesz ustawić ograniczenie szerokości (contentView) na równe scrollviews superview, ale wybierz usuń usuń w czasie kompilacji, ponieważ będziesz dodawać to ograniczenie programowo. To tylko dlatego, że IB nie narzeka ostrzeżeniami.

extension UIView {

    func setupContentViewForViewWithScroll(contentView vwContent : UIView) {
        //Set constraint for scrollview content
        let constraint = NSLayoutConstraint(item: vwContent, attribute: NSLayoutAttribute.Width, relatedBy: .Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant: self.bounds.size.width)
        vwContent.addConstraint(constraint)
        self.layoutSubviews()
    }

}

A w kontrolerze widoku viewDidLayoutSubviewspo prostu nazywam tę metodę:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    self.view.setupContentViewForViewWithScroll(contentView: vwContent)
}

0

Wiem, że jest to rozwiązanie dla laika, a nie to, co Apple sugeruje w dokumencie, ale zadziałało u mnie dwukrotnie, z inną zawartością i można je bardzo szybko skonfigurować: W widoku scenorysu kontroler wstaw UIView. W UIView wstaw widok tabeli, dynamiczny, 0 prototypowych komórek, styl zwykły lub zgrupowany. W widoku tabeli wstaw widok przewijania, w widoku przewijania wstaw zawartość. To wszystko, brak ustawień w kontrolerze widoku niestandardowego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.