UIWebView pagination - iphone

I have a large html content to render in a UIWebView, I want to display the content in pages just like a book and the user uses buttons to navigate the pages. Is there any way to calculate the height of html content that fits in the webview without scrolling?

If anyone comes around, in iOS7 and more you can just do :
self.webview.paginationBreakingMode = UIWebPaginationBreakingModePage;
self.webview.paginationMode = UIWebPaginationModeLeftToRight;

for (id subview in self.webView.subviews)
{
if ([[subview class] isSubclassOfClass:[UIScrollView class]])
{
((UIScrollView *)subview).pagingEnabled = YES;
break;
}
}

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];
}

UIWebView Scrolling

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"]

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.

iPhone SDK - UIWebView has a grey box over it

Sometimes, my UIWebView will have a grey box over part or all of the content. I can't make heads or tails of why it's happening. It happens regularly for certain content.
Thanks!
--Update--
It seems to occur when the webview is not immediately viewable on the screen -- ie i've got a scrollview, and the webview is below the fold.
--Update #2--
When I bring the content above the fold, it loads fine most of the time. There are still instances when the grey box is still showing up. The weird part is if i double-tap it, it finishes loading the content just fine. bizarre
--Update #3--
Okay, so it seems to be that if my uiwebview has a height greater than 1000px, a grey box appears on the rest of the content below 1000px. A double-tap reveals the actual content.
All UIViews have a size limit of 1024x1024 pixels. This is stated at the end of the Overview section of the UIView documentation.
If your web view must have more than 1024px of content, you will have to take it out of the parent scroll view and let it manage scrolling on its own.
Nudging the UIScrollView in the UIWebView it fixes this for me:
[UIScrollView *webScroller= [[webView subviews] lastObject];
[webScroller setContentOffset:CGPointMake(0,1) animated:NO];
[webScroller setContentOffset:CGPointMake(0,0) animated:NO];
I have been dealing with this glitch as well, and have opened a bug report at apple.
I would have commented above, but I don't have the 50 rep yet.
For anyone else encountering this glitch, send them a report, I included a full project demonstrating it, with a few screenshots from another app I am working on.
The more bug reports they get on a topic, the more likely they are to address it, apparently.
https://bugreport.apple.com/
I've got the same problem. I put a UIWebView inside a big TableViewCell (>1024px) and when I scroll to the bottom of the cell, there is this grey box.
But, if I put a UILabel (also with a big size > 1024px), there is no grey box. So I think this has nothing to do with a max height of a UIView (BTW I can't find anything about this so called 1024 max height). I think it's more a UIWebView issue.
The solution for me is to reload the content of the webview when the grey box appears. Actually, I just have a HTMLString to load so I call [webview loadHTMLstring:] again, and the grey box disappear.
Hope that will help
I found a very intersting post about that, it solved the problem for me :
link ttp://pinchzoom.com/blog/items/view/1386/one-of-the-problems-with-the-uikit-at-the-moment-is-an-issue-embedding-a-uiwebview-within-a-table
Hope that helps
I've used stringByEvaluatingJavaScriptFromString plus moving UIWebView origin.
Design overview: I had a set of controls(UIImage in this example) above(I mean frame.origin.y) UIWebView. So, layout was:
UIView
UIScrollView
UIImageView
UIWebView
Since UIWebView doesn't support scrolling in such hierarchy I've rearrange it like:
UIView
UIScrollView
UIImageView
UIWebView
My view controller is delegate for UIWebViewDelegate and UIScrollViewDelegate.
Then,
- (void)viewDidLoad
{
// set delegates
self.scrollView.delegate = self;
self.webView.delegate = self;
// store original UIWebView position in ivar
webViewPosY = self.webView.frame.origin.y;
// load html into UIWebView
[self.webView loadHTMLString:someHTML baseURL:nil];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
// get UIWebView size and store in ivar
webSize = [self.webView sizeThatFits:CGSizeMake(1.0,1.0)];
// set proper content height for UIScrollView
CGSize contentSize = self.scrollView.contentSize;
contentSize.height = webViewPosY + webSize.height;
self.scrollView.contentSize = contentSize;
// set UIWebView's frame height same as UIScrollView has
CGRect wf = self.webView.frame;
wf.size.height = self.scrollView.frame.size.height;
self.webView.frame = wf;
}
// scrolling logic:
// 1. if origin of UIWebView > 0 then move UIWebView itself
// 2. if origin of UIWebView == 0 then scroll with javascript
// 3. if origin is 0 and whole html is scrolled then move UIWebView again(this happens to support scroll "bouncing", or if you have some views below UIWebView
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
CGFloat scrollPosY = self.scrollView.contentOffset.y;
// (1) and (2) ifs
// how much to move UIWebView
CGFloat scrollOriginY = (scrollPosY >= webViewPosY) ? webViewPosY : scrollPosY;
// how much to scroll via JS
CGFloat scrollJSY = scrollPosY - scrollOriginY;
// (3) if
if ( scrollPosY > (webSize.height - scrollViewSize.height + webViewPosY ) )
scrollOriginY += scrollPosY - (webSize.height - scrollViewSize.height + webViewPosY);
// scroll with JS
[self.webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"document.body.scrollTop = %f;", scrollJSY]];
// move UIWebView itself
CGRect wf = self.webView.frame;
wf.origin.y = webViewPosY - scrollOriginY;
self.webView.frame = wf;
}
This works just fine for me.
I ran into the same issue when dynamically resizing a UIWebView. Here's what worked for me:
#define LAYER_FOR(ui) [(ui) layer]
#define FRAME_FOR(ui) [LAYER_FOR((ui)) frame]
#define SET_FRAME_FOR(ui, frame) [LAYER_FOR((ui)) setFrame: (frame)]
+ (void) setHeightTo: (CGFloat *) height_ptr forView: (UIView *) a_view {
CGFloat height = *height_ptr;
CGRect existing_frame = [[a_view layer] frame];
existing_frame.size.height = height;
// need to reassign the same frame !?
NSLog(#"setting text view: %# to height: %f", a_view, (float) height);
SET_FRAME_FOR(a_view, existing_frame);
}
+ (void) resizeWebView: (UIWebView *) webView {
NSString *js = #" \
var __html_element = document.getElementsByTagName('html')[0]; \
var __height_string = document.defaultView.getComputedStyle(__html_element, null).getPropertyValue('height'); \
__height_string.replace('px', ''); \
";
NSString *heightString = [webView stringByEvaluatingJavaScriptFromString: js];
float height = [heightString floatValue];
if (height != UI_VIEW_HEIGHT(webView)) {
[self setHeightTo: &height forView: webView];
// resize scrollView inside webview to the same height
UIScrollView *webScroller = [[webView subviews] lastObject];
[self setHeightTo: &height forView: webScroller];
}
}
I called this code from webview's delegate 'webViewDidFinishLoad:' method.
Basically, the trick is to resize the webScroller inside webview.
Thanks to Padraig for the suggestion to nudge the webview's subview (the scrollview).