UIWebView Scrolling - iphone

I load an HTML form in my UIWebView and it so happens that my UIWebView starts from the middle of the view and extends. I have to lock this webView from scrolling and put it on top of a scrollView to allow scrolling. The webView shouldn't scroll internally. I have tried this
[[webView.subviews objectAtIndex:0] setScrollEnabled:NO];
but I am not able to stop the webView from scrolling internally when I load a form in it that has textFields clicking on which brings up the keyboard. When I load plaintext, I am able to get the desired behavior. I want to stop the webView from autoscrolling and handle the scrolling myself using the scrollView that lay beneath the webView. It might not make sense to most of you that I am reinventing the wheel but the requirement is such.
Can anybody suggest what to do?

You can try,
for (id subview in webView.subviews)
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
if([subview respondsToSelector:#selector(setScrollingEnabled:)]) [subview performSelector:#selector(setScrollingEnabled:) withObject:NO];
or you need to stop bouncing of the webview you can try this.
for (id subview in webView.subviews)
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
((UIScrollView *)subview).bounces = NO;
Hope this helps.

Try running this after the webview has loaded (i.e. in the proper delegate method):
[webView stringByEvaluatingJavaScriptFromString:#"document.getElementsByTagName('body')[0].style.overflow='hidden'"]
If you have access to the HTML, you could also just set the correct style on the body element:
body { overflow: hidden; }
If you do either of these, you need to make sure that you make the UIWebView tall enough to display everything. You can get the height by running this (also after the webview has loaded):
CGFloat height = [webView stringByEvaluatingJavaScriptFromString:#"document.body.scrollHeight"]

Related

How to replace SwipeGestureRecognizer action in a UIWebView

I'm trying to present local html5 content in a set of 5 UIWebViews.
The idea is that the user would swipe to go to the 4 direction so I got 5 UIWebViews with bouncing disabled :
leftWebView.scrollView.bounces = NO;
middleWebView.scrollView.bounces = NO;
rightWebView.scrollView.bounces = NO;
upWebView.scrollView.bounces = NO;
downWebView.scrollView.bounces = NO;
We would assume that no scroll is possible in the webviews because the html pages displayed are smaller than the iPad Screen.
These web views are loaded so that the transition animated just by moving their center to be smooth.
So is there a way to change the swipe action performed by the gesture recognizers in the UIWebView?
I tried to put 4 SwipeGesturesRecognizers (one per direction) directly on the webViews but for some reason the gestures recognizer loose track of their WebViews when I swap references with :
UIWebView *tmp = leftWebView;
leftWebView = middleWebView;
middleWebView = rightWebView;
rightWebView = tmp;
I tried to use 4 SwipeGesturesRecognizers (one per direction) on a UIView on top of the window, but the taps are now blocked by this view, so that the user is not able anymore to interact with clickable elements.
You could add a custom UISwipeGestureRecognizer to your webView .. and disable the scroll in the webView like this
UIScrollView *scroll = [[self.webView subviews] lastObject];
if([scroll isKindOfClass:[UIScrollView class]])
{
scroll = (UIScrollView*)scroll;
[scroll setScrollEnabled:NO];
}

How do I make UIWebView scroll to the top?

Is there a way to make a UIWebView scroll to the top when I touch say a UISearchView within the same viewController (without using Javascript).
Something like this:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
[myWebView scrollToTop]; //pseudocode
}
In other words, what happens when I touch the top bar can also happen programmatically.
CGPoint top = CGPointMake(0, 0); // can also use CGPointZero here
[myWebView.scrollView setContentOffset:top animated:YES];
(Note that if you have set myWebView.scrollView.contentInset.top you will want to take that into account instead of just scrolling to CGPointZero.)
Here's a really ugly, terrible way to do this. I'm answering this to show you what never to do.
for (UIView *subview in webView.subviews)
{
if ([subview isKindOfClass:[UIScrollView class]])
[(UIScrollView*)subview setContentOffset:CGPointZero animated:YES];
}
If you don't want to use JavaScript there's no public API method to do this. UIWebViews don't inherit from scroll views, so you can't use any of the usual methods. As you've figured out, it's possible to do with JavaScript. You can try to find the actual scroll view in the UIWebView, but it's all undocumented and not really a good thing to do in a production app.
Update - as of iOS 5 you can now get direct access to a web view's UIScrollView - see Reconquistador's answer for more information.
Scroll the UIWebView by calling JavaScript through Objective-C:
NSString *script = #"scrollTo(0, 0)";
[webView stringByEvaluatingJavaScriptFromString:script];
For smooth scrolling, use a library like jQuery:
NSString *script = #"$('html, body').animate({scrollTop:0}, 'slow')";
[webView stringByEvaluatingJavaScriptFromString:script];
Access the UIWebView's scrollview and set YES to method scrollsToTop;
WebView.scrollView.scrollsToTop = YES;
Hope this helps!
Swift 3.x
webView.scrollView.setContentOffset(CGPoint.zero, animated: true)
I don't believe you will find any officially supported method to do what you are wanting.
This works for me:
CGPoint topOffset = CGPointMake(0, 0);
//[scrollView setContentOffset: topOffset animated: YES];
[[[webView subviews] lastObject] setContentOffset:topOffset animated:YES];
Where webView is the subclass of the UIWebView, of course.
why not just touch the status bar of your device. for all the scrollView based controls, tableView, webView, scrollView, there is a :
The scroll-to-top gesture is a tap on the status bar; when this property is YES, the scroll view jumps to the top of the content when this gesture occurs. The default value of this property is YES.
Displaying a PDF in a UIWebView, I found you can jump to the top simply by reloading the document.

iphone: View on top of UIWebView?

I'm working on a browser app, and I have an address bar on top the UIWebView. On MobileSafari if you scroll down, the address bar starts to move to the top, out of the screen, and the UIWebView doesn't scroll. Only when the address bar disappears completely, it starts to scroll. I would like to have this effect in my app as well.
What's the best way to implement this?
Thanks
The only way to implement this requires iOS 5.
In iOS 5, UIWebView has an UIScrollView subview.
And use the following code:
Set a area for the address bar:
[[myWebView scrollView] setContentInset:UIEdgeInsetsMake(64, 0, 0, 0)];
Move the address bar using the scrollview delegate:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if(scrollView.contentOffset.y>=-64&&scrollView.contentOffset.y<30)
{
topBar.frame=CGRectMake(0,-44-scrollView.contentOffset.y, 320, 44);
}
else if(scrollView.contentOffset.y<-64)
topBar.frame=CGRectMake(0,20, 320, 44);//Lock the position
}
There is a way, but I am not sure if it is a bit too hacky. First search for the scrollview within the webview, then alter the contentInset and finally add the searchbar(for example) to the scrollview. The following code is just an example, I did not set any frames correctly and 40 is just a made up height for the searchbar. I am not sure if this will work in every iOS Version.
UIWebView * myWebView = [[UIWebView alloc] init]
UISearchBar * mySearchBar = [[UISearchBar alloc] init];
for (NSObject * aSubView in [myWebView subviews]) {
if ([aSubView isKindOfClass:[UIScrollView class]]) {
UIScrollView * theScrollView = (UIScrollView *)aSubView;
theScrollView.contentInset = UIEdgeInsetsMake(40, 0, 0, 0);
[theScrollView addSubview:mySearchBar];
}
}
PeakJi's solution works but is a bit laggy. A better solution would be adding an observer to the UIScrollView's content offset, something like
[scrollview addObserver:self forKeyPath:#"contentOffset"
options:NSKeyValueObservingOptionNew context:nil];
You can find more document on NSKeyValueObserving protocol at
https://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html
Come to think of it, it is simply a scrolling view with an address bar stuck on the top, and both the web view and the bar always move together. Now, lets say you create a scroll view and add two subviews, the address bar and the web view (one below the other). It is to be noted that the height of the web view is determined and fixed after the page has been loaded (in webViewDidFinishLoad:).
Hence, it is simply a scrolling view whose contentSize is equal to the height of the bar + the height of the web view. Now, by default the web view allows scrolling, as it has a scroll view as a subview. As only the outer scroll view should be scrolling, it is required that the web view's scrolling be turned off. For that, fetch the first subview (that's the scroll view) and disable its scrolling using:
(UIScrollView*)[myWebView.subviews objectAtIndex:0].scrollEnabled = NO;

How to reset UIWebView's zoom? I'm already using scalesPagesToFit = YES;

I've been looking for the past week for the answer to this question.
I have a UIWebView, inside of a UIScrollView. Everything works great, but I want the content of the UIWebView to reset its zoom, when the orientation changes.
In the HTML inside the UIWebView, I set the width of the viewport (w/ a meta tag) to "device-width" and then on the Obj-C side, I set the scalesPagesToFit = YES;
I've tried resetting the zoom with javascript; by replacing the meta tags in runtime; reloading; accessing the UIScrollView inside of the UIWebView; etc...
but with no success.
Any of you gods know a workaround?
The only one I can think off is to recreate the UIWebViews every time we change the orientation, but that makes them flash to white whilst rendering content, which looks terrible :(
Any thoughts?
Many thanks,
Andre
I'm just guessing here and haven't tried, but AFAIK a UIWebView has a UIScrollView child. So one should be able to do:
for (UIScrollView *scroll in [myWebView subviews]) {
// Make sure it really is a scroll view and reset the zoom scale.
if ([scroll respondsToSelector:#selector(setZoomScale:)])
[scroll setZoomScale:1.0];
}
On iOS 5+ you have access to scrollView.
Just do:
[webView.scrollView setZoomScale:1.0];
If you want to do it programmatically this is the only way I could find to accomplish it: (specify your own sizes if you wish, i was attempting to zoom out after typing into a form field)
UIScrollView *sv = [[webViewView subviews] objectAtIndex:0];
[sv zoomToRect:CGRectMake(0, 0, sv.contentSize.width, sv.contentSize.height) animated:YES];
Update:
Downscaling wasn't working properly when using
[[[webView subviews] lastObject] setZoomScale:0.25];
The quality of the images being downscaled on the page was awful. Doing:
[[[webView subviews] lastObject] setZoomScale:0.25 animated:YES];
Fixed it. So that last line is the one you could use.
webView was subclassed of a UIWebView which lies on some IB file. I didn't use the Viewport at all. I find that one should pick by either doing this from the Cocoa Touch side or use JS.
I used:
webView.scalesPageToFit = YES;
I wonder if there's a way of resetting the scalesPageToFit.
Adapting from Captnwalker1's answer, I came up with this:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if(toInterfaceOrientation ==UIInterfaceOrientationPortrait||toInterfaceOrientation==UIInterfaceOrientationMaskPortraitUpsideDown)
{
currentScrollView = [[webView subviews] objectAtIndex:0];
[currentScrollView zoomToRect:CGRectMake(0, 0, currentScrollView.contentSize.width, currentScrollView.contentSize.height) animated:NO];
}
else
{
currentScrollView = [[webView subviews] objectAtIndex:0];
[currentScrollView zoomToRect:CGRectMake(0, 0, currentScrollView.contentSize.width, currentScrollView.contentSize.height) animated:NO];
}
}
So load your webview image, and the image will reset it's size when rotated.

Stop scrolling to top in UIWebView - iPhone

I have placed following javascript in my html file.
<script TYPE="text/javascript">
function srk(){
document.ontouchmove = function(e){
e.preventDefault();
}
}
</script>
I am scrolling my webview by following code with some animation.
[myWebView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat: #"window.scrollTo(0,%i);",414*self.initialScrollPosition]];
Everything going right, but on problem that I am facing is as follows.
Whenever User/I tap on the status bar of iPhone, WebView Bydefault scrolls to top.
This should not be done.
Is it possible to prevent inbuilt functionality ?
I know one of the option is as follows.
((UIScrollView *)[[myWebView valueForKey:#"_internal"] valueForKey:#"scroller"]).scrollsToTop = NO;
But is it valid to do ?
You can add a very tiny UIScrollView in the window. Then tapping the status bar won't scroll the web view to top.
A more straightforward way to do this would be to set the scrollsToTop property of the UIScrollView in the WebView to NO.
for(UIView *view in [myWebView subviews]) {
if([view isKindOfClass:([UIScrollView class])]) {
[(UIScrollView *)view setScrollsToTop:NO];
}
}
I have tested this on iOS 4.0 and 4.3 (iOS 5 seems to not need this).
adapted from this.