Context
Single ViewController
Two UIWebView objects as subviews of a UIScrollView are in this ViewControllers view
The ViewController is the delegate of both UIWebViews
The delegate method - (void)webViewDidFinishLoad:(UIWebView *)webView gets called twice as expected for both UIWebViews
I'm setting the height of these UIWebViews using sizeThatFits once their content has loaded (in the webViewDidFinishLoad method
What I want to do
Once both WebViews have loaded their content I want to set the height of the UIScrollView that they are in relative to the WebViews height. Basically I want the UIScrollView to be tall enough to scroll all the way through the text in the UIWebViews.
Possible Solutions I've thought of
Have a counter within the webViewDidFinishLoad method, and when it is equal to the amount of WebViews on the view call a method that sets the height of the UIScrollView.
Call set height of UIScrollView in webViewDidFinishLoad - it will be called multiple times, but the last call will be the correct height.
Question
How do I work out when both webViews have loaded in a "better" way than the possible solutions above?
I think you're making this too complicated. As you suggest at the end of your question, why not just set the height (contentSize.height, I believe is what you want) with each webViewDidFinishLoad:? You can test to see which webview is the tallest and set the height to that value:
CGSize size = CGSizeMake(320, 0);
size.height = webView1.frame.size.height + webView2.frame.size.height;
scrollView.contentSize = size;
IMO it's not a great idea to be placing multiple webviews inside a scrollview (although I've done it before too...) Could you consider getting rid of the scroll view altogether and having a single webview (which is self-scrolling) and has two iframe elements, which each display your original webview1/webview2 content?
Related
I have a bunch of UIWebViews in the cells of a UITableView. When tapped, I'm opening up a new view and recreating the UIWebView in the cell.
Obviously it would be greatly advantageous if I could use the webView instance that already exists, saving the user from opening the web page twice.
However, when I tried passing the webView and adding to its new parent UIView object, the webview seems to have issues resizing itself. Its simply not adjusting its height and width, even though I explicitly adjust it and confirm the new frame size. Is it not possible to resize a webview's frame? Or am I missing something?
Thanks
I'm almost positive this is possible. I've done it with custom videoPlayerViews, passed them from a collectionViewCell to a viewController.
Some ideas:
Make sure that you remove the webView from its original superview before adding it as a subview of its new superview.
Make sure your autoResizingMask and constraints are set up properly with respect to the new superview, and destroyed with respect to the original superview.
I'm struggling with wrapping my head around using UITableView with UIWebView within UIScrollView. The interface I'm trying to build consist of a header (containing a few labels, always the same size), UIWebView (can be any height, I'm scaling it dependently on the content) and a UITableView (also can have any number of elements). I want user to scroll through the whole content like he would be scrolling through one page.
I realize that Apple doesn't recommend using UITableView or UIWebView within UIScrollView. However, I'm having a hard time to think about some workaround.
Is it possible to get the desired effect done the way I'm trying to do it right now? If not, what would be the cleanest or at least working way of doing it?
(I'm currently using Xcode 6 beta 3 / swift)
You can set your UIScrollView's contentSize.height to the sum of your UITableView's contentSize.height and the height of your UIWebView's content.
To get it, just add this to your ViewController after setting it as your UIWebView's delegate:
func webViewDidFinishLoad(webView: UIWebView!) {
let output = webView.stringByEvaluatingJavaScriptFromString("document.body.offsetHeight;")
let contentHeight = (output as NSString).floatValue
}
Then, you just have to set the frame height of your tableView and webView to their content's height and place them correctly in the scroll view.
Hope this will help,
I am building an app which gets its HTML contents from a web feed (JSON). The length of the pages vary from a single line to hundreds of lines.
Although the UIWebView is perfectly capable of scrolling, I need a UITableView under the UIWebView to display additional menu items. This means that I need the whole view to scroll and not just the UIWebView. This also means that the UIWebView shouldn't scroll at all and that it should scale to the content.
The UIImageView is the header, the UIWebView is the content, the UITableView is the footer menu. The hidden button is there to create the segue to itself.
I resize the UIWebView with this code:
-(void)webViewDidFinishLoad:(UIWebView *)webView{
WebView.frame = CGRectMake(WebView.frame.origin.x, WebView.frame.origin.y, WebView.frame.width, [WebView sizeThatFits:CGSizeZero].height);
}
That works for the UIWebView and it gets correctly resized. The UITableView however is shown over resized UIWebView, it does not get pushed down by the bigger UIWebView at all.
Secondly, this view has a Segue to itself (its like a wiki structure with internal references), which works like a charm. But when I go back a page the UIWebView stays its original size again, it doesn't get resized. The segue makes the app forget the new size of the UIWebView somehow.
As you can see I'm struggling with this, everything seems so static and absolute while i need some 'relative positioning'. But then again I'm new to iOS programming and thinking like a webdeveloper. Why doesn't the segue remember the UIWebView height? Why Isnt the UITableView pushed down? What am I missing here? (I must be missing something big right?)
To adjust TableView as per Webview ,set your TableView frame using height of webview inside the webViewDidFinishLoad itself,
-(void)webViewDidFinishLoad:(UIWebView *)webView{
WebView.frame = CGRectMake(WebView.frame.origin.x, WebView.frame.origin.y, WebView.frame.width, [WebView sizeThatFits:CGSizeZero].height);
TableView.frame = CGRectMake(TableView.frame.origin.x,WebView.frame.size.height + 20.0,TableView.frame.size.width,TableView.frame.size.height); // like this
}
You can position you controls after one another like below
CGRect rect=imageView.frame;
float y=rect.origin.y;
//We need to just change the y from the next control so for the next control y would be.
y=y+rect.size.height+20.0;// 20.0 px padding
//Now use the above rect to set the frame for next control in your case its webview
rect=webView.frame;
rect.origin.y=y;
webView.frame=rect; //Re-Assign with changed y value
//Now move to next
y=y+rect.size.height+20.0;// 20.0 px padding
rect=tblView.frame;
rect.origin.y=y;
tblView.frame=rect; //Re-Assign with changed y value
Your all the controls should be aligned vertically one after another, you can put this code in a method, and call the method, whenever you feel the frame is changing for any control..
Hope this helps..
Ok. here is the story:
I have a UIWebView in full screen, width = 768
It loads several images and those images are in one line, which means the UIWebView will scroll only horizontally.
Now, I set the UIScrollView inside the UIWebView to pagingEnabled = YES. So the scroll on the UIWebView will move page by page.
The problem is that every image's width is about 900. I won't scale them down and if I scroll the UIWebView, from the 2nd page on, always 132points of previous image will show. This is not good for me.
So how can I manipulate the UIWebView or the UIScrollView inside the UIWebView so that each scroll will move a page of 900 points, if the view's frame width is 768?
The constraints are:
I can't change its contentSize
I can't change its bounds or frame
I say these constraints because UIWebView will change them on its own purpose when it loads contents.
Anyone would like to join this brain storming?
Thanks
I'm thinking you're going to need to set a UIScrollView delegate that tracks touches beginning and ending. More specifically, scrollViewDidEndDragging:willDecelerate is what I'm thinking you'll need to use, as it fires the instant a user lifts their hand from the device.
First, pagingEnabled=NO seems obvious, we're going to have to control our own paging. Which, I don't feel is too tough. Track the direction of the scrolling in scrollViewDidScroll:, so that we have some global set:
BOOL isGoingRight = YES or NO (NO means the last movement was to the left)
float PAGESIZE = 900.0;
Here's how my scrollview delegate method would look like that handles paging.
- (void) scrollViewDidEndDragging:(UIScrollView*)_scrollView willDecelerate:(BOOL)willDecelerate {
float offsetProportion = _scrollView.contentOffset.x/_scrollView.frame.size.width;
//depending upon our direction, round up or down
int page = isGoingRight? ceilf(offsetProportion): floorf(offsetProportion);
//manually finish the scroll
[_scrollView scrollRectToVisible:CGRectMake(page*PAGESIZE, 0, _scrollView.frame.size.width, _scrollView.frame.size.height) animated:YES];
}
I didn't test this, you may or may not need to disable touches at points.
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/