Zatrzymać UIWebView przed „odbijaniem się” w pionie?


225

Czy ktoś wie, jak zatrzymać odbijanie UIWebView w pionie? Mam na myśli, gdy użytkownik dotknie ekranu iPhone'a, przeciągnie palcem w dół, a widok strony internetowej pokaże puste miejsce nad stroną, którą załadowałem?

Sprawdziłem następujące możliwe rozwiązania, ale żadne z nich nie działało dla mnie:

http://www.iphonedevsdk.com/forum/iphone-sdk-development/996-turn-off-scrolling-bounces-uiwebview.html

http://forums.macrumors.com/showthread.php?t=619534

Jak zatrzymać odbijanie UIScrollView w poziomie?


1
Mam nadzieję, że zastanowiłeś się nad konsekwencjami użyteczności wyłączenia tej funkcji. Jest tam z jakiegoś powodu. To powiedziawszy, jestem również ciekawy, jak byś to zrobił.
Michael Haren

Sposób, w jaki mam osadzony w mojej aplikacji, wydaje się niewiarygodnie z niektórymi innymi elementami widoku, które mam, a jedyny raz, gdy się nie pojawia, to kiedy następuje odbicie ... Zdecydowanie dobra uwaga!
Brad Parks

Odpowiedzi:


424
for (id subview in webView.subviews)
  if ([[subview class] isSubclassOfClass: [UIScrollView class]])
    ((UIScrollView *)subview).bounces = NO;

... wydaje się działać dobrze.

Zostanie również przyjęty do App Store.

Aktualizacja : w iOS 5.x + istnieje prostszy sposób - UIWebViewma scrollViewwłaściwość, dzięki czemu kod może wyglądać następująco:

webView.scrollView.bounces = NO;

To samo dotyczy WKWebView.


To działa. Nie jest wymagane żadne podklasowanie, a jeśli Apple kiedykolwiek zmieni hierarchię UIWebView, nie powinno się zawiesić.
leolobato,

2
Ta poprawka wydaje się działać tylko w moim symulatorze OS 4.1, a nie w iPhonie OS 3.1.3. Czy ktoś wie, czy ta poprawka działa tylko w niektórych wersjach systemu operacyjnego?
Dan J

@MirukRusin - Jak możesz zagwarantować, że ta aplikacja zostanie zaakceptowana na podstawie trzech wierszy kodu? : P
Moshe,

@Mirek - Przegapiłeś mój punkt. Skąd wiesz, że nic innego w aplikacji nie zostanie odrzucone?
Mosze

6
To działało dobrze dla mnie. Dla wygody dodałem kategorię, aby UIWebViewmóc dzwonić w [webView setBounces:NO]dowolnym miejscu.
zekel

46

Patrzyłem na projekt, który ułatwia tworzenie aplikacji internetowych jako pełnoprawnych aplikacji do zainstalowania na iPhonie, o nazwie QuickConnect , i znalazłem rozwiązanie, które działa, jeśli nie chcesz, aby ekran był w ogóle przewijalny, co w moim przypadku Ja nie.

W wyżej wspomnianym poście dotyczącym projektu / blogu wspominają o funkcji javascript, którą można dodać, aby wyłączyć odbijanie, co zasadniczo sprowadza się do tego:

    document.ontouchmove = function(event){
        event.preventDefault();
    }

Jeśli chcesz dowiedzieć się więcej o tym, jak to zaimplementować, po prostu pobierz QuickConnect i sprawdź ... Ale w zasadzie wszystko, co robi, to wywołanie javascript na stronie ładowania ... Próbowałem po prostu umieścić go w nagłówku mojego dokumentu, i wydaje się, że działa dobrze.


Ta odpowiedź jest poprawnym sposobem na zatrzymanie pionowego przewijania zawartości w UIWebView.
Jessedc

3
Mogłeś podać całą odpowiedź, po pierwsze, nie chcę pobierać całego kodu źródłowego innej aplikacji i nawet nie mogę go znaleźć. Twoja odpowiedź polega na tym, że inna strona internetowa jest taka sama jak wtedy, gdy odpowiedziałeś.
Jonathan.

Ta odpowiedź i powyższa zaakceptowana odpowiedź wydają się być czasami wymagane. W moim przypadku stwierdziłem, że jeśli widok strony internetowej nie został jeszcze załadowany, bounce będzie tam, dopóki powyższy JS nie zostanie załadowany do systemu. Wydaje się, że odpowiedź jest taka, że ​​zarówno powyższa, jak i przyjęta odpowiedź są czasami wymagane.
Kalle,

3
jak powiedział Jessedc, przestanie to przewijać w pionie, nie tylko podskakując. oznacza to, że jeśli masz div, który wymaga przewijania, nie będzie się przewijał.
memical

18

Cóż, wszystko co zrobiłem, aby to osiągnąć, to:

UIView *firstView = [webView.subviews firstObject];

if ([firstView isKindOfClass:[UIScrollView class]]) {

    UIScrollView *scroll = (UIScrollView*)firstView;
   [scroll setScrollEnabled:NO];  //to stop scrolling completely
   [scroll setBounces:NO]; //to stop bouncing 

}

Działa dobrze dla mnie ... Również zaznaczona odpowiedź na to pytanie jest taka, że ​​Apple odrzuci, jeśli użyjesz go w aplikacji na iPhone'a.


3
To najlepszy i najprostszy sposób. To powinna być zaakceptowana odpowiedź! +1
PostCodeism

3
Nie rób tego - moja aplikacja została odrzucona za użycie pierwszego wiersza. Zmarnowałem tyle czasu dla mnie. użyłem [[webView.subviews lastObject] setScrollEnabled: NO]; a Apple powiedział, że to prywatny API i dlatego go odrzucił; mam zamiar przesłać teraz ponownie, ale użyłem „userInteractionEnabled: NO”, ponieważ nie potrzebuję żadnych aktywnych linków w aplikacji.
Veeru

UIWebView dziedziczy z UIView. UIView ma wywiady właściwości. Co tu jest prywatne? Wszystko to można znaleźć na developer.apple.com
Valerii Pavlov,

3
Mam w tym sklepie coś z 4 aplikacji. Twoja aplikacja została wyraźnie odrzucona z innego powodu. to nie jest prywatny interfejs API.
Zigglzworth,

4
To naprawdę nie jest dobry pomysł. Opierasz się na tym, że UIScrollViewjest to pierwszy przegląd, UIWebViewktóry może tak być na razie, ale może to łatwo zmienić w przyszłych (nawet drobnych) aktualizacjach iOS lub określonych konfiguracjach. Powinieneś naprawdę zrobić foriterację, subviewsaby ją znaleźć UIScrollView(to naprawdę nie jest tak dużo pracy i przynajmniej masz gwarancję, że dostaniesz UIScrollViewi nie zawiesisz swojego programu ...
Jonathan Ellis

17

W zestawie iOS 5 SDK można uzyskać dostęp do widoku przewijania powiązanego z widokiem internetowym, zamiast iterować jego widoki podrzędne.

Aby wyłączyć „odbijanie” w widoku przewijania, możesz użyć:

myWebView.scrollView.bounces = NO;

Zobacz Odwołanie do klasy UIWebView .

(Jeśli jednak potrzebujesz obsługi wersji SDK przed 5.0, powinieneś postępować zgodnie z radą Mirka Rusina .)



9

Ostrzeżenie. Użyłem setAllowsRubberBanding: w mojej aplikacji Apple go odrzuciło, stwierdzając, że niepubliczne funkcje API są niedozwolone (cytowanie: 3.3.1)



3

Metoda Brada działała dla mnie. Jeśli go użyjesz, możesz uczynić go trochę bezpieczniejszym.

id scrollView = [yourWebView.subviews objectAtIndex: 0];
if ([scrollView respondsToSelector: @selector (setAllowsRubberBanding :)])
{
    [scrollView performSelector: @selector (setAllowsRubberBanding :) withObject: NO];
}

Jeśli jabłko coś zmieni, wtedy odbicie wróci - ale przynajmniej twoja aplikacja się nie zawiesi.


3

Na iOS5 tylko wtedy, gdy planujesz pozwolić użytkownikom na powiększanie zawartości strony internetowej (np. Dwukrotne dotknięcie) ustawienie odrzuceń nie jest wystarczające. Musisz także ustawić właściwości alwaysBounceHorizontal i alwaysBounceVertical na NO, w przeciwnym razie, gdy pomniejszą (kolejne podwójne dotknięcie ...), domyślnie, odbije się ponownie.


2

Przejrzałem kolekcję widoków podrzędnych UIWebView i ustawiłem ich tła na [UIColor blackColor], ten sam kolor co tło strony. Widok nadal będzie się odbijał, ale nie pokaże brzydkiego ciemnoszarego tła.


1
W rzeczywistości jest to dość zły, ponieważ jeśli Apple kiedykolwiek zmieni wewnętrzne UIWebView, ten hack może się zepsuć.
bpapa,

2

Wygląda mi na to, że UIWebView ma UIScrollView. Możesz do tego użyć udokumentowanych interfejsów API, ale odbijanie jest ustawione dla obu kierunków, a nie indywidualnie. To jest w dokumentach API. UIScrollView ma właściwość bounce, więc coś takiego działa (nie wiem, czy jest więcej niż jeden widok przewijania):

NSArray *subviews = myWebView.subviews;
NSObject *obj = nil;
int i = 0;
for (; i < subviews.count ; i++)
{
    obj = [subviews objectAtIndex:i];

    if([[obj class] isSubclassOfClass:[UIScrollView class]] == YES)
    {
        ((UIScrollView*)obj).bounces = NO;
    }
}

2

Zirytowało mnie to, że UIWebView nie jest widokiem przewijania, więc utworzyłem niestandardową podklasę, aby uzyskać widok przewijania widoku strony internetowej. Ten suklass zawiera widok przewijania, dzięki czemu można dostosować zachowanie widoku internetowego. Punktami zwrotnymi tej klasy są:

@class CustomWebView : UIWebview
...

- (id) initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
// WebViews are subclass of NSObject and not UIScrollView and therefore don't allow customization.
// However, a UIWebView is a UIScrollViewDelegate, so it must CONTAIN a ScrollView somewhere.
// To use a web view like a scroll view, let's traverse the view hierarchy to find the scroll view inside the web view.
for (UIView* v in self.subviews){
    if ([v isKindOfClass:[UIScrollView class]]){
        _scrollView = (UIScrollView*)v; 
        break;
    }
}
return self;

}

Następnie, podczas tworzenia niestandardowego widoku internetowego, możesz wyłączyć odbijanie za pomocą:

customWebView.scrollView.bounces = NO; //(or customWebView.scrollView.alwaysBounceVertically = NO)

Jest to świetny sposób ogólnego zastosowania do tworzenia widoku internetowego z możliwością dostosowywania zachowania przewijania. Jest tylko kilka rzeczy, na które należy uważać:

  • jak w przypadku każdego widoku, musisz również przesłonić - (id) initWithCoder: jeśli używasz go w Konstruktorze interfejsów
  • kiedy początkowo tworzysz widok internetowy, jego rozmiar zawartości jest zawsze taki sam jak rozmiar ramki widoku. Po przewinięciu Internetu rozmiar zawartości reprezentuje rozmiar faktycznej zawartości internetowej w widoku. Aby obejść ten problem, zrobiłem coś hacky - wywołanie -setContentOffset: CGPointMake (0,1) animowane: TAK, aby wymusić niezauważalną zmianę, która ustawi odpowiedni rozmiar zawartości widoku internetowego.

2

Natknąłem się na to, szukając odpowiedzi i ostatecznie po prostu miałem szczęście, że udało mi się znaleźć odpowiedź. Zrobiłem

[[webview scrollView] setBounces:NO];

i zadziałało.


2

To działało dla mnie i też pięknie (używam phonegap z webView)

[[webView.webView scrollView] setScrollEnabled:NO];

lub

[[webView scrollView] setScrollEnabled:NO];

1

Wypróbowałem nieco inne podejście, aby zapobiec przewijaniu i odbijaniu obiektów UIWebView : dodając rozpoznawanie gestów, aby zastąpić inne gesty.

Wygląda na to, że UIWebView lub jego widok przewijania używa własnego rozpoznawania gestów panoramy do wykrywania przewijania użytkownika. Ale zgodnie z dokumentacją Apple istnieje uzasadniony sposób na zastąpienie jednego rozpoznawania gestów innym. Protokół UIGestureRecognizerDelegate ma metodę gestRecognizer: shouldRecognizeSimultentlyWithGestureRecognizer: - który pozwala kontrolować zachowanie dowolnych kolidujących gestów.

Więc to, co zrobiłem, było

w metodzie viewDidLoad kontrolera widoku:

// Install a pan gesture recognizer                                                                                        // We ignore all the touches except the first and try to prevent other pan gestures                                                     
// by registering this object as the recognizer's delegate                                                                                        
UIPanGestureRecognizer *recognizer;                                                                                                               
recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanFrom:)];                                                   
recognizer.delegate = self;                                                                                                                       
recognizer.maximumNumberOfTouches = 1;                                                                                                            
[self.view addGestureRecognizer:recognizer];                                                                                                          
self.panGestureFixer = recognizer;                                                                                                                  
[recognizer release]; 

następnie metoda przesłonięcia gestu:

// Control gestures precedence                                                                                                                            
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer                                                                                        
        shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer                                                  
{                                                                                                                                                         
        // Prevent all panning gestures (which do nothing but scroll webViews, something we want to disable in                                          
        // the most painless way)                                                                                                                         
        if ([otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])                                                                        
        {
            // Just disable every other pan gesture recognizer right away                                                                             
            otherGestureRecognizer.enabled = FALSE;
        }                                                                                                                                                  
        return NO;                                                                                                                                        
}              

Oczywiście ta metoda delegowania może być bardziej złożona w prawdziwej aplikacji - możemy selektywnie wyłączać inne moduły rozpoznające, analizując inny plik GestureRecognizer.view i podejmując decyzję na podstawie tego, jaki to widok.

I wreszcie, ze względu na kompletność, metodę, którą zarejestrowaliśmy jako program obsługi panoramowania:

- (void)handlePanFrom:(UIPanGestureRecognizer *)recognizer 
{ 
    // do nothing as of yet
}

może być pusty, jeśli wszystko, czego chcemy, to anulować przewijanie i podskakiwanie widoków internetowych, lub może zawierać nasz własny kod do implementacji takich ruchów panoramy i animacji, których naprawdę chcemy ...

Jak dotąd eksperymentuję z tymi wszystkimi rzeczami i wydaje się, że działają mniej więcej tak, jak tego chcę. Jednak nie próbowałem jeszcze przesyłać żadnych aplikacji do iStore. Ale wydaje mi się, że do tej pory nie korzystałem z niczego nieudokumentowanego ... Jeśli ktoś uzna to inaczej, proszę o informację.





0

Jednym z podstron UIWebViewpowinien być UIScrollView. Ustaw jego scrollEnabledwłaściwość na, NOa widok sieci będzie całkowicie wyłączony.

Uwaga: technicznie korzysta z prywatnego interfejsu API, dlatego aplikacja może zostać odrzucona lub ulec awarii w przyszłych wersjach systemu operacyjnego. Użyj @tryirespondsToSelector


Wypróbowałem to i to działa, gdy próbuję ... Dziwnie, mogę uzyskać dostęp i ustawić scrollView.bounces (bez efektu), ale kiedy próbuję ustawić scrollEnabled, to powoduje błąd ...
Brad Parks

Uważam, że widok podrzędny nosi nazwę UIScroller, a nie UIScrollView. UIScroller to nieudokumentowana i nieobsługiwana klasa, która ma wiele wspólnego z UIScrollView, ale nie można polegać na tym, że wszystko działa tak samo i nie zmienia się w przyszłych wersjach systemu operacyjnego.
Marco

Zrobiłem to na aplikacji na iPada (nie iPhone) z systemem iOS 3.2 i byłem w stanie uzyskać UIScrollView z mojego UIWebView. Z powodzeniem dostosowałem ten widok, aby zmienić coś więcej niż tylko zachowanie podczas podskakiwania, dzięki czemu mogę potwierdzić, że działa na iPadzie. Moja aplikacja nie przeszła przez sklep z aplikacjami, ale nie sądzę, żeby pojawił się problem z nieudokumentowanymi interfejsami API. Sprytną częścią tego rozwiązania jest to, że po prostu przemierzasz hierarchię UIView i używasz UIScrollView - oba są doskonale koszerne.
Rolf Hendriks,

0

Sprawdź bounceswłaściwość UIScrollView. Quoth the Apple docs:

Jeśli wartość właściwości to YES(domyślna), widok przewijania jest odbijany, gdy napotyka granicę zawartości. Odbicie wizualne wskazuje, że przewijanie doszło do krawędzi treści. Jeśli wartość wynosi NO, przewijanie zatrzymuje się natychmiast na granicy zawartości bez podskakiwania.

Upewnij się, że używasz właściwego UIScrollView. Nie jestem pewien, jak wygląda hierarchia UIWebView, ale widok przewijania może być rodzicem, a nie dzieckiem UIWebView.


0

Aby wyłączyć UIWebViewprzewijanie, możesz użyć następującego wiersza kodu:

[ObjWebview setUserInteractionEnabled:FALSE];

W tym przykładzie ObjWebviewjest typu UIWebView.


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.