An editable UIwebview in an UIScrollView. Issue with scrolling - ios

I have an editable UIWebView into an UIScrollView.
I disabled the scrollview and the bounces on the UIWebView to only rely on the UIScrollView' scrollview.
Each 0.1 second, I have a Timer which detects if the UIWebView content has changed since last check. If so, and if the caret is greater than a given position, the offset fo the scrollView is updated, and the result is pretty good.
My issue is when I go back to edit an already written text.
The UIWebView scrolls on its own view, and the text disappears.
I'd like to use the UIScrollView instead.
Here are two pictures showing the issue:
EDIT: Here is a video showing the bug: http://dl.dropbox.com/u/9666723/Bug.mov
Thanks for any piece of help.

Related

UIScrollView with pagingEnabled = YES and a very large contentSize, the same issue as the iBooks

I met this weird problem when I had an UIScrollView with pagingEnable = YES and a very large contentSize (let's say over 20000000).
Basically I want to write a PDF viewer just like the iBooks (showing one page in the screen). So the bounds of the UIScrollView is just the size of the screen, but the contentSize will be "the page number of the PDF" * "page width". This worked for small PDF, but with large PDF, the paging function seems broken.
For example, I had a 94MB PDF with over 20000 pages, the width of contentSize will be over 20000000. For the first 3000 pages (approximately), the paging works fine: the scrollview always bounces the page to the center of screen. But after 3000 pages, you will find that the bouncing becomes slow, not that smooth. And start from some page, the bouncing totally broken: the page will not show in the center, but stuck at somewhere else, just like pagingEnable = NO. It doesn't bounce anymore.
At first I thought it was something wrong with my code, but I suprisingly find that the iBooks has the same problem! I can't even trigger the toolbar with a single tap after scrolling the last page. So I'm wondering is this an iOS bug?
More Info: When debugging, I found that after the finger touched up, -scrollViewDidScroll: gets called for many times, which is normal, because the UIScrollView starts bouncing when pagingEnable = YES. But the problem is that the -scrollViewDidEndDecelerating: never gets called. Seems like the bouncing animation is broken at some middle point. Weird.
the PDF is only 94MB
File size does not equal the size in memory. PDFs are compressed, but they have to be uncompressed for display.
What's also important is that you don't need a scroll view that's as wide as the entire book - you only need a scroll view that's three pages wide. This is because a) you're hopefully already recycling your page views, and b) because only one page is visible on the screen at any one time you can move the content around as and when you need to.
Is there any reason you are not using a UIPageViewController, which is designed pretty much for this purpose?
Bottom line: there's no reason for your scroll view to be that wide. It only need to be a few pages wide, and you can move the views around to give the illusion the scroll view is much bigger than it actually is. If you search StackOverflow you'll almost certainly find a number of answers that do basically this.

iOS: Stop ScrollView from making room when selecting textfield at top

I've scoured through several questions asking about how to prevent scrolling when selecting a first responder however nothing I find seems to work for this issue.
I have a UITextField above my table view at the very top of my page. When the user selects it (or when I do it programmatically) it drops down a bit, seemingly giving room for options such as "paste" or autocorrect (which I've disabled). I'd like to prevent this from happening.
I've tried setting the scroll position myself, which it initially does, but then it instantly jumps down a bit. Is there a way I can make the paste/edit bubble appear below the textfield (like it does with textfields in the header)? I'm thinking perhaps that will prevent it from jumping downwards, but I can't find information on this.
I'm completely stuck so any help is appreciated. Links, vague suggestions, whatever. Thank you.
Try embedding your text field in a scroll view the same size as your text field.
The reason why this should work is because when a text field becomes first responder, it only scrolls the scroll view that is its most recent ancestor in the view hierarchy. If it only finds the dummy scroll view, whose content size should not exceed its bounds size, then no scrolling should occur in either scroll view.

UIWebview in UIScrollview send vertical scroll event to scrollview

So i have a UIWebView that is meant to only scroll horizontally, and its in a UIScrollView that is only meant to scroll vertically. I have almost managed to achieve this, but i have a slight problem.
The UIWebiew's scroll content height is set to the height of the webviews frame, so that it wont scroll vertically, but even when this is the case, it still seems to consume the vertical scrolling event (sometimes), since i can see the side scroll bar show, but it wont scroll (and doesnt scroll the scrollview that the webview is contained in).
It needs to be like this because there are some elements that need to scroll vertically with the webview, but not horizontally (think of the safari app how the addressbar scrolls with the webview)
does anyone know how i would pass the vertical scroll event through but keep the horizontal scroll event for the UIWebView?
i had a look at this answer but its not quite what im looking for
update:
so typically just after i ask the question i find a suitable answer on another question... (had been searching for a few hours now) this answer should do the trick for me, ill give it a go and report back
Just set
scrollView.alwaysBounceVertical = NO;
scrollView.contentSize = CGSizeMake(
scrollView.frame.size.width, scrollView.contentSize.height);
scrollView.showsVerticalScrollIndicator = NO;
Edit:
doesn't seems to work. Too bad..
Try implementing
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gst
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)gst2 {
return YES;
}
..in your view containing the scrollView and webView, or even the scrollView itself (containing the webView).
So the solution i found that i posted in the question works for the most part, it does exactly what i need, but for some reason after a webpage loads, it scrolls the headerbar away showing just the webpage, which isnt the end of the world but its not pretty. it seems the event fires after the webViewDidFinishLoad: so i cant just reposition it back to the top. Ill keep tinkering around, maybe i can find out why its doing it.

iOS: How do I keep the UIToolbar (that I've added to UIWebView.scrollView) from going off screen?

Hopefully i can explain this clearly. I have a UIWebView and I've added a UIToolbar to it's scrollView (another works [webView.scrollView addSubview:myToolbar];). So everything is fine and dandy until i try to pinch zoom that's when the toolbar stays in the corner of the screen, so basically it doesn't stay in the middle. If you haven't guessed already, I'm trying to make a duplicate of safari's behavior. I need to have the UIToolbar to not be affected by the pinch gesture. Any ideas on how to do this? I've read other posts but it doesn't seem to really give an answer. Any help is appreciated :)
You have to create a parent UIView, say rootV, in which you embed myToolbar at the top, and then webView.
This stops the pinching from affecting myToolbar, however this make it stick at the top, and not move beyond the screen when the user scrolls vertically myWebView.
To get the same behavior as Safari, you have to check the vertical scrolling in myWebView, and based on it you expand up or down the size of rootV. Assuming you fixed the height of myToolbar but made webView fill the rest, it should just work.

how to forward UIWebView scroll to UIScrollView ? (conditionally)

I have a UIWebView inside UIScrollView.
This idea is to be able to create more reading space on screen when user scroll the webpage upwards - by scrolling the UIScrollView upwards till the toolbar is visible, and obviously when the toolbars is nomore visible actually scroll the webpage to show more content that's on the page.
IPhone Safari browser does exactly the same functionality.
see screenshot (first) for default behavior i am getting - i guess because : the scrolling message is consumed by the webview since the touch/scroll is happening directly on webview area.
what i would like to do here is programatiicaly decide when to forward the 'upward scroll' to the UIScrollivew and when not to.
Any tips on how to get around this will be so helpful. Thanks!!
The UIWebView class reference discourages embedding a UIWebView in a UIScrollView:
Important: You should not embed UIWebView or UITableView objects in
UIScrollView objects. If you do so, unexpected behavior can result
because touch events for the two objects can be mixed up and wrongly
handled.
However I suppose you still want to implement your feature ;-)
Idea 1: Don't embed the UIWebView in a UIScrollView, instead run javascript using UIWebView's stringByEvaluatingJavaScriptFromString: method, modifying the DOM to add a toolbar below. If required, you can callback objective-c code from any buttons pushed on the toolbar by registering some custom URL schemes.
Idea 2: Don't embed the UIWebView in a UIScrollView, but in a normal UIView. Building on Vignesh's suggestion, listen for your webView's inner scrollView's scrollViewDidScroll: callback via the delegate, checking the contentOffset vs. the contentSize's height each time the callback is called. Once they are equal, it means you got to the bottom. Once this happens you can animate your toolbar's frame to "enter" the containing UIView and "push" the webView's frame away.
Idea 3: Ignore Apple's recommendation, and embed the UIWebView in a UIScrollView. Building on Vignesh's suggestion, listen for your webView's inner scrollView's scrollViewDidScroll: callback via the delegate, checking the contentOffset vs. the contentSize's height each time the callback is called. Once they are equal, it means you got to the bottom. Once this happens set the userInteractionEnabled property of the webView to NO, and set it to YES on the scrollView which contains the webView and the toolbar. Hopefully the scroll will continue smoothly enough. Of course you have to listen to the containing scroll view in the same way to determine when to switch back the userInteractionEnabled.
A variation on this idea would be to just set userInteractionEnabled to NO for the webView, but set the webView's frame's height to match its contentSize, and also enlarge the contentSize of the containing scrollView accordingly.
Both variations have the drawback that in some cases you won't be able to do things such as click on links :-( But maybe that's good enough for your case. At least in the first variation it's not so bad.
You can add a searchbox and uiwebview in a UIscrollview one below another. To get the content offset when webview is scrolled you can use the following code snippet.
UIScrollView* currentScrollView;
for (UIView* subView in testWebView.subviews) {
if ([subView isKindOfClass:[UIScrollView class]]) {
currentScrollView = (UIScrollView*)subView;
currentScrollView.delegate = (id)self;
}
}
Now you can change your base scrollview offset's y value to the offset value you get from the scrollview didscroll delegate method.
Advanced ScrollView Techniques
https://developer.apple.com/videos/wwdc/2011/

Resources