UIScrollView nie przewija

129

Mam jeden, UIScrollViewktóry zawiera wiele UIImageViews, UILabels itp ... etykiety są znacznie dłuższe niż te UIScrollView, ale kiedy uruchamiam aplikację, nie mogę kliknąć i przewinąć w dół ...

Dlaczego tak się dzieje?

Dzięki

znak
źródło
New 3/26/2013 Natknąłem się na łatwiejszy sposób na zrobienie tego bez kodu (ustawienie contentSize) stackoverflow.com/a/15649607/1705353
Dickey Singh

Odpowiedzi:

171

Zawsze dobrze jest pokazać cały działający fragment kodu:

// in viewDidLoad (if using Autolayout check note below):

UIScrollView *myScrollView;
UIView *contentView;
// scrollview won't scroll unless content size explicitly set

[myScrollView addSubview:contentView];//if the contentView is not already inside your scrollview in your xib/StoryBoard doc

myScrollView.contentSize = contentView.frame.size; //sets ScrollView content size

Swift 4.0

let myScrollView
let contentView

// scrollview won't scroll unless content size explicitly set

myScrollView.addSubview(contentView)//if the contentView is not already inside your scrollview in your xib/StoryBoard doc

myScrollView.contentSize = contentView.frame.size //sets ScrollView content size

Nie znalazłem sposobu na ustawienie contentSize w IB (od Xcode 5.0) .

Uwaga: jeśli używasz Autolayout, najlepszym miejscem na umieszczenie tego kodu jest wewnątrz -(void)viewDidLayoutSubviewsmetody.

Bogatyr
źródło
12
Nie zapomnij ustawić myScrollView.delegate = selfTAKŻE, jeśli to nadal nie działa, odpowiedź poniżej tej ma ŚWIETNĄ radę (przejdź do swojego xib / StoryBoard i upewnij się, że "AutoLayout" jest wyłączone). Porada od profesjonalistów: Możesz również dołączyć <UIScrollViewDelegate>do pliku .h, jeśli chcesz wykonywać takie czynności, jak programowe przewijanie UIScrollView.
Albert Renshaw
1
@AlbertRenshaw, powinieneś był dodać odpowiedź, więc mogłem dać ci +1 :) Autoukład był moim problemem .... doprowadzał mnie do szaleństwa przez około 4 godziny.
logiksolog
2
Wprowadzenie kodu viewDidLayoutSubviewssprawiło, że zadziałało.
Amr Lotfy
Dla mnie problem polegał na tym, że nie trzeba było przewijać, ponieważ wszystko mieściło się na ekranie.
Daniel Springer
122

Jeśli nie możesz przewinąć widoku nawet po prawidłowym ustawieniu contentSize , upewnij się, że odznaczyłeś "Użyj autoukładu" w Interface Builder -> File Inspector.

user1539652
źródło
165
Alternatywnie możesz ustawić contentSize w viewDidLayoutSubviews : i zostanie zastosowany po zakończeniu automatycznego układu.
Chris Vasselli
2
@ "Chris Vasselli" rozwiązał mój problem .. GR8 .. :-)
Ayaz
3
Komentarz Chrisa powinien być osobną odpowiedzią!
ninjaneer
1
Dziękuję bardzo Chris Vasselli! Po włączeniu automatycznego układu nie będzie działać w viewDidLoad, ale działa z viewDidLayoutSubviews!
Romain
1
Woah, nigdy wcześniej nie zauważyłem tych wszystkich komentarzy! Cieszę się, że mogłem pomóc tak wielu z was! Właśnie opublikowałem osobną odpowiedź, więc mam nadzieję, że będzie łatwiej ją znaleźć.
Chris Vasselli
69

Musisz ustawić contentSizewłaściwość widoku przewijania, aby przewijał się prawidłowo.

Jeśli używasz autoLayout, trzeba ustawić contentSizesię viewDidLayoutSubviewsw celu użycia go do stosowania po dopełnia autoLayout.

Kod mógłby wyglądać tak:

-(void)viewDidLayoutSubviews
{
    // The scrollview needs to know the content size for it to work correctly
    self.scrollView.contentSize = CGSizeMake(
        self.scrollContent.frame.size.width,
        self.scrollContent.frame.size.height + 300
    );
}
Chris Vasselli
źródło
Dzięki za tonę. To zadziałało, ponieważ z jakiegoś powodu, nawet gdy ustawię wartość contentSizena rozmiar contentView, rozmiar scrollView i contentView wydaje się być ustawiony jako taki sam. Ale ustawienie wysokości na contentSizewartość większą niż wysokość contentViewzadziałało.
Skywalker
viewDidLayoutSubviewsmogą być wywoływane wiele razy w trakcie cyklu życia, więc ryzykujesz, że zwiększysz wysokość większą niż oczekiwano.
anon_nerd
@anon_nerd po prostu sprawdź, czy został już wywołany i dodaj wysokość, jeśli nie
Daniel Springer
45

Powyższa odpowiedź jest prawidłowa - aby przewijać się, konieczne jest ustawienie rozmiaru treści.

Jeśli używasz konstruktora interfejsu, dobrym sposobem na to jest użycie atrybutów wykonawczych zdefiniowanych przez użytkownika. Na przykład:

wprowadź opis obrazu tutaj

Jasper Blues
źródło
to nic dla mnie nie dało.
coolcool1994
4
Ups, zdjęcie pokazuje {0, 0}, ale oczywiście musisz wpisać wystarczająco duże liczby. . to podejście będzie działać tylko w przypadku prostych widoków, w przypadku których znasz z góry rozmiar treści. . . (w rzeczywistości dla złożonych widoków i tak zalecam czysty kod).
Jasper Blues
Znacznie mniej hakerskie niż robienie tego programowo. Dziękuję Ci!
Jake Stoeffler
1
@JakeStoeffler witamy! :) Kiedy używam IB, lubię trzymać tam całą konfigurację (nie pofragmentowaną). Ale kiedy sprawy stają się skomplikowane (widżety widoków wielokrotnego użytku, adaptery modeli, manipulacje warstwami, animacje CA, itp.), Wolę w pełni programowe widoki. . . bardziej płynnie.
Jasper Blues
Próbowałem tego, działa, gdy pojawia się widok, ale przy zmianie orientacji contentSize zdefiniowany na powyższym ekranie jest ignorowany, a mój dziennik mówi, że contentSize jest ustawiony z powrotem na 0,0. Masz jakiś pomysł, jak to naprawić?
Shoogle,
40

Spróbuj zmienić rozmiar zawartości do ogromnych liczb. Nie mogłem zrozumieć, dlaczego mój widok przewijania nie przewija się, nawet jeśli rozmiar jego zawartości wydaje się być większy niż rozmiar kontrolny. Odkryłem, że jeśli rozmiar zawartości jest mniejszy niż potrzebny, to również nie działa.

self.scrollView.contentSize = CGSizeMake(2000, 2000);

Zamiast 2000 możesz umieścić własne duże liczby. A jeśli to działa, oznacza to, że rozmiar zawartości nie jest wystarczająco duży, gdy zmieniasz rozmiar.

Pełnomocnik nie jest potrzebny do działania widoku przewijania.

Denis Kutlubaev
źródło
2
Geniusz - taki prosty sposób na sprawdzenie, co się dzieje. Wielkie dzięki!
The Crazy Chimp,
13

Upewnij się, że właściwość contentSize widoku przewijania jest ustawiona na prawidłowy rozmiar (tj. Wystarczająco duży, aby objąć całą zawartość).

Ben Gottlieb
źródło
1
czy muszę to robić programowo? czy mogę to zrobić w IB?
Mark
Jeśli używasz IB, możesz to ustawić z tego miejsca - patrz poniżej. . (Oddzielna odpowiedź, więc mogę dołączyć fotki).
Jasper Blues
7

Odznaczenie „Użyj automatycznego układu” załatwiło mi sprawę.

Środowisko: xCode 5.0.2 Storyboards ios7

Gaurav Kumkar
źródło
5

W moim przypadku musiałem ustawić delaysContentTouchesna true, ponieważ wszystkie obiekty wewnątrz scrollView przechwytywały zdarzenia dotyku i obsługiwały siebie, zamiast pozwolić, aby sam scrollView obsługiwał to.

devios1
źródło
Mam ten sam problem. Problem dla mnie polega na tym, że zmieniając wartości DelaysContentTouches na true, zakończysz rysunkami o niższej jakości wykonanymi ołówkiem jabłkowym. Ale to jest
skrajny
4

Ustaw contentSizewłaściwość UIScrollviewin ViewDidLayoutSubviewsmethod. Coś takiego

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()

    scrollView.contentSize = CGSizeMake(view.frame.size.width, view.frame.size.height)
}
Vinayak Parmar
źródło
3

Pomysł, dlaczego widok przewijania nie przewija się, ponieważ ustawiono rozmiar zawartości do przewijania mniejszy niż rozmiar widoku przewijania, co jest błędne. Aby poruszać się po nim podczas przewijania, należy ustawić rozmiar zawartości większy niż rozmiar widoku przewijania.

Ten sam pomysł z powiększaniem, ustawiasz minimalną i maksymalną wartość powiększania, która zostanie zastosowana przez akcję powiększania.

Witamy :)

Abo3atef
źródło
3

Jeden mały dodatek, wszystkie powyższe to rzeczywiste powody, dla których widok przewijania może nie być przewijany, ale czasami bezmyślnie może to być powód szczególnie, gdy widok przewijania jest dodawany za pomocą kodu, a nie IB, być może dodałeś swoje podziały do ​​widoku nadrzędnego, a nie scrollview powoduje, że podwidok nie przewija się

i utrzymuj rozmiar zawartości ustawiony i większy niż nadrzędna ramka widoku (duhh !!)

Abhinav Singh
źródło
3

Udało mi się to za pierwszym razem. Z automatycznym układem i wszystkim, bez dodatkowego kodu. Następnie widok kolekcji stał się bananem, awaria w czasie wykonywania, nie mogłem znaleźć przyczyny, więc usunąłem go i odtworzyłem (używam Xcode 10 Beta 4. Czułem się jak błąd), a potem przewijanie zniknęło. Jednak widok kolekcji znów zadziałał!

Wiele godzin później ... właśnie to naprawiło. Miałem następujący układ:

UIView

  • Bezpieczna strefa
  • Przewiń widok
    • Widok zawartości

Wszystko jest w ograniczeniach. Obszar bezpieczny jest definiowany automatycznie przez system. W najgorszym przypadku usuń wszystkie ograniczenia dotyczące przewijania i widoków treści i nie pozwól, aby IB resetował / tworzył je za Ciebie. Wykonaj je ręcznie, to działa.

  • Dla widoku przewijania zrobiłem: Wyrównaj końcowe / górne do bezpiecznego obszaru. Jednakowa szerokość / wysokość do bezpiecznego obszaru .
  • Dla widoku zawartości zrobiłem: Wyrównaj końcowe / wiodące / górne / dolne do nadzoru (widok przewijania)

zasadniczo chodzi o to, aby widok zawartości pasował do widoku Scrollview, który pasuje do bezpiecznego obszaru.

Ale jako takie nie zadziałało. W widoku zawartości brakuje wysokości. Próbowałem wszystkiego, co mogłem, a jedyną rzeczą, która robiła sztuczkę, był widok zawartości, który utworzył widok zawartości, przeciągając kontrolkę do siebie . To zdefiniowało stałą wysokość, której wartość została obliczona z Rozmiar kontrolera widoku (zdefiniowanego jako dowolny, dłuższy niż rzeczywisty wyświetlacz, zawierającego wszystkie moje podglądy) i wreszcie zadziałało!

Michele Dall'Agata
źródło
Nie ma za co! Wiem dokładnie, jak się czułeś .. ;-)
Michele Dall'Agata
Thaaaaks, spędziłem wiele godzin i to rozwiązało mój problem
Andoni Da Silva.
3

Jeśli otrzymujesz komunikat (IOS8 / swift), viewDidLayoutSubviewsktóry nie istnieje, użyj zamiast tego poniższego

override func viewDidAppear(animated: Bool)

To naprawiło to dla mnie

Jason G
źródło
2

Coś, o czym wcześniej nie wspomniano!

Upewnij się, że gniazdko zostało prawidłowo podłączone do scrollView! Powinien mieć wypełnione kółko, ale nawet jeśli masz wypełnione kółko, scrollView może nie być podłączony - więc sprawdź dokładnie! Najedź na kółko i zobacz, czy podświetlony zostanie rzeczywisty widok przewijania! (To był przypadek dla mnie)

//Connect below well to the scrollView in the storyBoard
@property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
coolcool1994
źródło
2

W większości przypadków kod jest poprawny, jeśli korzystałeś z samouczka, ale wielu początkujących nie wie, że scrollView NIE będzie normalnie przewijał symulatora. Przewijanie ma być wykonywane tylko wtedy, gdy naciskasz podkładkę pod mysz i jednocześnie przewijasz. Wielu doświadczonych użytkowników XCode / Swift / Obj-C jest do tego przyzwyczajonych, więc nie wiedzą, jak może to zostać przeoczone przez początkujących. Cześć :-)

@IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(scrollView)
    // Do any additional setup after the view
}

override func viewWillLayoutSubviews(){
    super.viewWillLayoutSubviews()
    scrollView.contentSize = CGSize(width: 375, height: 800)
}

Ten kod będzie działał doskonale, o ile będziesz robić to, co powiedziałem powyżej

flo527
źródło
2

Dodaj UIScrollViewDelegatei dodając następujący kod do viewDidAppearmetody naprawiło to za mnie.

@interface testScrollViewController () <UIScrollViewDelegate>

-(void)viewDidAppear:(BOOL)animated {
    self.scrollView.delegate = self;
    self.scrollView.scrollEnabled = YES;
    self.scrollView.contentSize = CGSizeMake(375, 800);
}
Trianna Brannon
źródło
1

Jeśli żadne z innych rozwiązań nie działa dla Ciebie, sprawdź dokładnie, czy Twój widok przewijania faktycznie jest UIScrollVieww programie Interface Builder.

W pewnym momencie w ciągu ostatnich kilku dni UIScrollView spontanicznie zmieniłem typ na a UIView, mimo że jego klasa powiedziała UIScrollViewinspektorowi. Używam Xcode 5.1 (5B130a).

Możesz utworzyć nowy widok przewijania i skopiować pomiary, ustawienia i ograniczenia ze starego widoku lub możesz ręcznie zmienić widok na a UIScrollVieww xibpliku. Porównałem i znalazłem następujące różnice:

Oryginał:

<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" directionalLockEnabled="YES" bounces="NO" pagingEnabled="YES" showsHorizontalScrollIndicator="NO" showsVerticalScrollIndicator="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Wsk-WB-LMH">
...
</scrollView>

Po spontanicznej zmianie typu:

<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" customClass="UIScrollView" id="qRn-TP-cXd">
...
</view>

Więc wymieniłem <view>żyłkę na moją oryginalną<scrollView> .

Ja również zastąpić bliską tag w widoku </view>z </scrollView>.

Pamiętaj, aby zachować ten sam identyfikator, co w bieżącym widoku, w tym przypadku: id = "qRn-TP-cXd".

Musiałem również opróżnić xib z pamięci podręcznej Xcode, usuwając dane pochodne aplikacji:

  • Xcode->Window->Organizer->Projects, wybierz projekt, w wierszu Dane pochodne kliknij Usuń ...

Lub jeśli używasz urządzenia:

  • Xcode->Window->Organizer->Device, wybierz swoje urządzenie-> Aplikacje, wybierz swoją aplikację, kliknij (-)

Teraz wyczyść projekt i usuń aplikację z symulatora / urządzenia:

  • Xcode->Product->Clean
  • iOS Simulator/device->pressi przytrzymaj app->click(X), aby go usunąć

Powinieneś wtedy być w stanie skompilować i uruchomić aplikację oraz ponownie mieć funkcję przewijania.

PS Nie musiałem ustawiać rozmiaru zawartości widoku przewijania viewDidLayoutSubviewsani wyłączać układu automatycznego, ale YMMV.

Zack Morris
źródło
1

Jeśli Twój scrollViewjest podziałem plikucontainerView jakiegoś typu, upewnij się, że scrollViewznajdujesz się w ramce lub w granicach containerView. Miałem to, containerView.clipsToBounds = NOco nadal pozwalało mi widzieć scrollView, ale ponieważ scrollViewnie znajdował się w jego granicach containerView, nie wykrywał zdarzeń dotykowych.

Na przykład:

containerView.frame = CGRectMake(0, 0, 200, 200);
scrollView.frame = CGRectMake(0, 200, 200, 200);
[containerView addSubview:scrollView];
scrollView.userInteractionEnabled = YES;

Będziesz mógł zobaczyć scrollView, ale nie będzie on otrzymywać interakcji użytkownika.

Chase Roberts
źródło
1

dodanie poniższego kodu viewDidLayoutSubviewsdziałało dla mnie z Autolayout. Po wypróbowaniu wszystkich odpowiedzi:

- (void)viewDidLayoutSubviews
{
    self.activationScrollView.contentSize = CGSizeMake(IPHONE_SCREEN_WIDTH, 620);

}

//set the height of content size as required
Inteligentny iPhone
źródło
1

Mój problem został rozwiązany przez:

  1. ustawienie contentSize w scrollView na dużą wysokość
  2. ALE musiałem również naprawić górne i / lub dolne ograniczenia na widokach w scrollView, co oznaczało, że wskaźniki przewijania pokazywały się na ekranie, ale zawartość nie przewijała się

Po usunięciu górnych i / lub dolnych ograniczeń związanych z bezpiecznym obszarem i / lub nadzorem, widoki wewnątrz scrollView mogły znowu się przewijać i nie były ustalone na górze i na dole ekranu!

Mam nadzieję, że to powstrzyma kogoś przed wielogodzinnym bólem związanym z tym konkretnym problemem.

Henry Heleine
źródło
1

kolejny zabawny przypadek:

scrollview.superview.userInteractionEnabled musi mieć wartość true

Zmarnowałem 2 + godziny, goniąc to tylko po to, aby dowiedzieć się, że rodzicem jest UIImageView, który oczywiście ma userInteractionEnabled == false

Anton Tropashko
źródło
0

Po nieudanych odpowiedziach udzielonych w tym wątku natknąłem się na ten artykuł z rozwiązaniem.

Istnieją dwie rzeczy, które nie są intuicyjne w konfigurowaniu widoku przewijania z automatycznym układem:

  1. Ograniczenia ustawione jako margines między widokiem treści a widokiem przewijania nie wpływają na rozmiar widoku treści. To naprawdę są marginesy. Aby to działało, widok treści powinien mieć stały rozmiar.
  2. Sztuczka związana ze stałym rozmiarem polega na tym, że możesz ustawić szerokość widoku zawartości równą szerokości widoku nadrzędnego widoku przewijanego. Po prostu wybierz oba widoki w drzewie po lewej stronie i dodaj ograniczenie równej szerokości.

To jest istota tego artykułu. Aby uzyskać pełne wyjaśnienie, w tym ilustracje, sprawdź to.

H. de Jonge
źródło
@PredragManojlovic Jak to może być bardziej ogólne niż to? Tylko w ten sposób mogę sprawić, by widok przewijania działał poprawnie przy użyciu automatycznego układu.
H. de Jonge
0

Okazało się, że z tego autoLayout numerze ... gdybym tylko dokonać ViewControllerwykorzystania UIViewzamiast UIScrollViewdo klasy ... a potem po prostu dodać UIScrollViewsobie ... że to działa.

Brian Rice
źródło
0

Miałem ten sam problem w IB.

Po ustawieniu wiodącego, końcowego, górnego i dolnego widoku scrollView na jego superView. Wprowadziłem następujące zmiany, aby umożliwić przewijanie widoku containerView, co zadziałało.

Aby scrollView przewijał się tylko w kierunku poziomym, utwórz ograniczenie za pomocą środka scrollView Y = ContainerView centerY

i aby umożliwić przewijanie w pionie, należy ustawić centerX w scrollView = CenterX w ContainerView

Nandu
źródło