Redrawing content of UIWebView - iphone

I have a bunch of webviews with static html content that I'm putting in a scroll view as pages. That works fine, but having 20 something full screen subviews of the scroll view is causing some lag. I solved that by only placing 5 at a time in there. The current view, and the two next and two previous.
The problem now is that any web view that is not a subview of the scroll view is not drawing correctly based on the device orientation. The frame of the webview is printing out correct, but the actual content is drawing in portrait mode. So there is essentially a strip of blank space to the right of the content.
How do I go about re rendering the content without reloading the page?
Here's the relevant code:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation) fromInterfaceOrientation{
[self resizeSubViews];
}
- (void) setupWebViews{
if(_webViews == nil)
_webViews = [[NSMutableArray alloc] init];
// This is where the navigation would come into play as far as loading up available web views
[_webViews removeAllObjects];
// for loop here to create web views
for (int i = 0; i < 20; i++) {
//CDCWebViewController *webView = [[[MyInternalWebView alloc] initWithFrame:_webViewWrapper.frame] retain];
MyInternalWebView *page = [[[MyInternalWebView alloc] init] retain];
[page loadRequest:[NSURLRequest requestWithURL:_url]];
[page setCdcIWVdelegate:self];
[page setTestIndex:i];
[page setPageIndex:i];
[_webViews addObject:page];
[self loadScrollViewWithPage:i];
}
[self clearUnusedWebViews:_pageControl.currentPage];
}
- (void) setupWebViewWrapper{
// a page is the width of the scroll view
_webViewWrapper.pagingEnabled = YES;
_pageControl = [[[UIPageControl alloc] init] retain];
_webViewWrapper.showsHorizontalScrollIndicator = NO;
_webViewWrapper.showsVerticalScrollIndicator = NO;
_webViewWrapper.scrollsToTop = NO;
_webViewWrapper.delegate = self;
_pageControl.numberOfPages = [_webViews count];
_pageControl.currentPage = 0;
}
- (void) resizeSubViews{
// The frame is set in IB
_webViewWrapper.contentSize = CGSizeMake(_webViewWrapper.frame.size.width * [_webViews count], _webViewWrapper.frame.size.height);
// Move the content offset.
_webViewWrapper.contentOffset = CGPointMake(_webViewWrapper.frame.size.width * _pageControl.currentPage, _webViewWrapper.contentOffset.y);
for (MyInternalWebView *subview in _webViewWrapper.subviews) {
// Reset the frame height and width here?
CGRect frame = _webViewWrapper.frame;
frame.origin.x = frame.size.width * subview.pageIndex;
frame.origin.y = 0;
[subview setFrame:frame];
}
}
//*****************************************************
//*
//* ScrollView Functions
//*
//*****************************************************
- (void)loadScrollViewWithPage:(int)page {
// Make sure we're not out of bounds
if (page < 0) return;
if (page >= [_webViews count]) return;
MyInternalWebView *webView = [_webViews objectAtIndex:page];
// Add the preloaded webview to the scrollview if it's not there already
if (nil == [webView superview]) {
CGRect frame = _webViewWrapper.frame;
//NSLog(#"width = %f", frame.size.width);
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
//NSLog(#"setting frame for page %d %#", page, NSStringFromCGRect(frame));
[webView setFrame:frame];
[_webViewWrapper addSubview:[_webViews objectAtIndex:page]];
// Now that the new one is loaded, clear what doesn't need to be here
[self clearUnusedWebViews:page];
}
}
- (void) clearUnusedWebViews: (NSInteger) page{
for (int i = 0; i < [_webViews count]; i++) {
if ((page - i) <= 2 && i - page <= 2) {
continue;
}
[[_webViews objectAtIndex:i] removeFromSuperview];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = _webViewWrapper.frame.size.width;
NSInteger page = floor((_webViewWrapper.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
_pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 2];
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
[self loadScrollViewWithPage:page + 2];
}

In resizeSubViews, change frames of web views from _webViews array, not scroll view subviews.
Addendum:
Put check in scrollViewDidScroll if page != _pageControl.currentPage and only then load scrollViewsWithPage.
Orientation change might and probably will trigger scrollViewDidScroll.
In clearUnusedWebViews use _pageControl.currentPage instead of page variable. When you're at 5th view and you're loading 7th, you're removing 4th and 3rd even I'd say your intention was to have 3,4,5,6,7 in scroll view at this time.

reload
Reloads the current page.
- (void)reload
Availability
Available in iOS 2.0 and later.
See Also
#property request
#property loading
– loadRequest:
– stopLoading
Declared In
UIWebView.h
UIWebView Class Reference

Related

UIScrollView with scrolling buttons issue

I want to create UIScrollView with scrolling buttons.So when user press left arrow button, scroll must scroll properly.
The issue is: when I click button 3 times quickly scroll can't scroll properly (because of many calls of scrollRectToVisible). May be I can stop current animation before next animation?
P.S. If I set [self scrollScrollViewToIndex:index animated:NO] everything works properly, but I need animation
Here is my code:
- (void)scrollScrollViewToIndex:(int)index animated:(BOOL)animated
{
NSLog(#"scrolled to index: %d", index);
CGFloat offsetX = CGRectGetWidth(_scrollMain.frame) * index;
CGRect scrollRect = CGRectMake(offsetX, 0, CGRectGetWidth(_scrollMain.frame), CGRectGetHeight(_scrollMain.frame));
[_scrollMain scrollRectToVisible:scrollRect animated:animated];
// [self.scrollMain setContentOffset:CGPointMake(offsetX, 0) animated:animated];
}
- (IBAction)leftArrowPressed:(id)sender
{
int indexOfVoucher = [_arrayVouchers indexOfObject:_voucher];
indexOfVoucher--;
self.voucher = [_arrayVouchers objectAtIndex:indexOfVoucher];
[self updateViewWithVoucherWithScrolling:YES];
}
- (IBAction)rightArrowPressed:(id)sender
{
int indexOfVoucher = [_arrayVouchers indexOfObject:_voucher];
indexOfVoucher++;
self.voucher = [_arrayVouchers objectAtIndex:indexOfVoucher];
[self updateViewWithVoucherWithScrolling:YES];
}
- (void)updateViewWithVoucherWithScrolling:(BOOL)withScrolling
{
int indexOfVoucher = [_arrayVouchers indexOfObject:_voucher];
_leftArrowButton.hidden = _rightArrowButton.hidden = NO;
if (indexOfVoucher == 0)
{
_leftArrowButton.hidden = YES;
}
else if (indexOfVoucher == [_arrayVouchers count] - 1)
{
self.rightArrowButton.hidden = YES;
}
if (withScrolling)
{
[self scrollScrollViewToIndex:indexOfVoucher animated:YES];
}
}
update:
working code according to Mar0ux's advice
- (void)scrollScrollViewToIndex:(int)index animated:(BOOL)animated
{
NSLog(#"scrolled to index: %d", index);
CGFloat offsetX = CGRectGetWidth(_scrollMain.frame) * index;
if (animated)
{
[UIView animateWithDuration:0.5
delay:0.0
options:UIViewAnimationCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState //Multiple options
animations:^ {
// [self.scrollMain setContentOffset:CGPointMake(offsetX, 0) animated:NO];
CGRect scrollRect = CGRectMake(offsetX, 0, CGRectGetWidth(_scrollMain.frame), CGRectGetHeight(_scrollMain.frame));
[_scrollMain scrollRectToVisible:scrollRect animated:NO];
}
completion:^ (BOOL finished) {
}];
}
else
{
CGRect scrollRect = CGRectMake(offsetX, 0, CGRectGetWidth(_scrollMain.frame), CGRectGetHeight(_scrollMain.frame));
[_scrollMain scrollRectToVisible:scrollRect animated:NO];
}
}
You can always animate the contentOffset property yourself and use UIViewAnimationOptionBeginFromCurrentState option. As soon as the second animation begins, the first will end, and by using current state option, the second animation will start from where the first left off.
A few suggestions:
1) do you really want the user hammering on the button while its scrolling? If so then I suggest that your UI design may need redesign.
2) when you perturb the UI in an action method, its best to post other UI actions by dispatching a block with the code to the main queue - the button hiliting will look better.
3) in your specific case, you could in the action method disable the button, then re-enable it when the scrolling has stopped.

set dynamic UIWebView as header in TableView

I set the UIwebview as a header in UITableview.UIWebview height and width are dynamic.Its come for local html files.
UIWebview and UITableview are under one scroll.
It works fine for iphone.Same method I wrote for ipad it works good.but one problem is there.
In ipad Header view and table view alignment is not proper .
Here is code.
Rootviewcotrollor is UITableviewControllor
Rootviewcontroller.m
- (void)viewDidLoad {
[super viewDidLoad];
self.title = #"Webview in UITableView";
webview = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 10)]; // Don't use CGRectZero here, won't work
webview.delegate = self;
webview.hidden = YES;
[webview loadRequest:[[NSURLRequest alloc]
initWithURL: [NSURL URLWithString:#"http://www.google.com/"]]];
[self.tableView setTableHeaderView:webview]; // Leave this, else you'll have rows to fill the rest of the screen
}
- (void) webViewDidFinishLoad:(UIWebView *)webView {
float newSize = [[webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.scrollHeight"] floatValue];
NSLog(#"Resizing webview from %.2f to %.2f", webView.frame.size.height, newSize);
webView.frame = CGRectMake(webView.frame.origin.x, webView.frame.origin.y, webView.frame.size.width, newSize);
webView.hidden = NO;
// We need to reset this, else the new frame is not used.
[self.tableView setTableHeaderView:webview];
}
For same code iphone output
And iPad output UITableview start slider ahead of the UIWebview.
I try to set frame of header but it's not working,it give webview and table view both have it's own scrollview which not needed.
What is solution for it?
Thank you.
Its a grouped table view that's why its alignment is not proper cause grouped table view takes some default size from x-origin and y-origin always... you can use plain table or set x of grouped table or increase x-origin of web view..
Have you tried this in your "webviewdidfinishedload" delegate
note that "MyWebView" is the webview that fires the delegate also "webViewHeight" is int value that after it you should add your custom control and it's declared as public this is snap from my working code.. that add uitableview after webview to add comments.
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGSize size = [MyWebView sizeThatFits: CGSizeMake(1.0f, 1.0f)]; // Pass any size here
CGRect frame = MyWebView.frame;
frame.size.height = size.height;
MyWebView.frame = frame;
webViewHeight = size.height + 200;
}

Two UIScrollView in one UIView

I am trying to add two UIScrollView's into one UIView, Both the scrollView's show up properly, the problem that I am having is how to determine which scrollView is scrolled because based on that I have to populate the images. This is what I am doing:
I have a ViewController with UIScrollViewDelegate.
In the loadView method of my ViewConroller, I do the following:
CGRect scrollViewFrame1;
CGPoint scrollViewPoint1;
scrollViewPoint1.x = 0;
scrollViewPoint1.y = 57;
CGSize scrollViewSize1;
scrollViewSize1.width = 320;
scrollViewSize1.height = 154;
scrollViewFrame1.size = scrollViewSize1;
scrollViewFrame1.origin = scrollViewPoint1;
CGRect scrollViewFrame2;
CGPoint scrollViewPoint2;
scrollViewPoint2.x = 0;
scrollViewPoint2.y = 258;
CGSize scrollViewSize2;
scrollViewSize2.width = 320;
scrollViewSize2.height = 154;
scrollViewFrame2.size = scrollViewSize2;
scrollViewFrame2.origin = scrollViewPoint2;
scrollView1 = [[UIScrollView alloc] initWithFrame:scrollViewFrame1];
scrollView2 = [[UIScrollView alloc] initWithFrame:scrollViewFrame2];
And then:
scrollView1.delegate = self;
scrollView2.delegate = self;
And then:
[self.view addSubView:scrollView1];
[self.view addSubView:scrollView2];
I have one scrollViewDidScroll: method, how do I determine which scrollView this method got invoked by, because based on that i need to populate different images for my scrollView.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//Code to populate the next or previous images for scrollView
// If it was one i am able to show the images
}
Thanks for the help.
Delegate methods send with it the object that sent the message (the UIScrollView in this case). So, all you have to do is check that against your instance variables of scrollView1 and scrollView2.
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView == scrollView1) {
//do stuff with scrollView1
} else if (scrollView == scrollView2) {
//do stuff with scrollView2
}
}
FYI
You can also set a tag for both of the scrollView to differentiate
scrollView1.tag=10;
scrollView2.tag=11;
[self.view addSubView:scrollView1];
[self.view addSubView:scrollView2];
In your delegate
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView1.tag==10) {
//do stuff with scrollView1
} else if (scrollView2.tag==11) {
//do stuff with scrollView2
}
}

I want to zoom in and zoom out in ScrollView. How's it possible?

I have a scroll view within one image. I just want to zoom in and zoom out the scroll view. How do I apply zoom in and and zoom out just by doing the pinch?
You have to set the maximumZoomScale and / or minimumZoomScale properties of your UIScrollView to something else than 1.0 to define how much you want the user to be able to zoom in/out ;)
Just add the file http://www.4shared.com/dir/-PGqZEXR/zoominzoomout.html to your project and call it through these functions.
Here im2 is UIVIEW, and I paste the image on it then passing this through viewDidLoad like this,
- (void)viewDidLoad {
[self loadFlowersInView:im2];
[self.view addSubview:im2];
}
Now attach this function like this,
- (void) loadFlowersInView: (UIView *) backdrop
{
NSString *create_button = nil;
// Add the flowers to random points on the screen
for (int i = 0; i < 1; i++)
{
MagPicAppDelegate *appdelegate = (MagPicAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *whichFlower = appdelegate.imageName;
UIImage *stemp = [UIImage imageNamed:#"approve.png"];
DragView *dragger = [[DragView alloc] initWithImage:stemp];
dragger.userInteractionEnabled = YES;
dragger.center = CGPointMake(160.0f, 140.0f);
[im2 addSubview:dragger];
[dragger release];
}
}
[self.view addSubview:im2];
[im2 release];
}

photoview using UIScrollViewController

I'm trying to make photo album like photo.app in iPhone. I know We have 'PhotoScroller' example from Apple (which I don't think I can copy and paste the code here due to the Non Disclosure Agreement, plus it's bit biggy to play with at the moment). However I found an another example from random search and it seems like based on the PhotoScroller (very simplified tough). The link for the example is ;
http://ykyuen.wordpress.com/2010/05/22/iphone-uiscrollview-with-paging-example/
I applied this code to my project to make photo album (and it scrolls, at least), but I found a problem. The problem is I cannot start from the page I want. The sample code only starts scrolling with Page One. Code itself seems 'really' simple but somehow I just cannot make it start from the page I choose.
Here is main part of the sample code that I found on the Internet. You can of course download the project the link above.
- (void)viewDidLoad {
NSLog(#"ScrollViewWithPagingViewContrller :: viewDidLoad");
[super viewDidLoad];
// view controllers are created lazily
// in the meantime, load the array with placeholders which will be replaced on demand
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
// a page is the width of the scroll view
scrollView.pagingEnabled = YES;
scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages, scrollView.frame.size.height);
scrollView.showsHorizontalScrollIndicator = NO;
scrollView.showsVerticalScrollIndicator = NO;
scrollView.scrollsToTop = NO;
scrollView.delegate = self;
pageControl.numberOfPages = kNumberOfPages;
pageControl.currentPage = 0;
// pages are created on demand
// load the visible page
// load the page on either side to avoid flashes when the user starts scrolling
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];}
- (void)loadScrollViewWithPage:(int)page {
NSLog(#"ScrollViewWithPagingViewContrller :: loadScrollViewWithPage");
if (page < 0) return;
if (page >= kNumberOfPages) return;
// replace the placeholder if necessary
MyViewController *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[MyViewController alloc] initWithPageNumber:page];
[viewControllers replaceObjectAtIndex:page withObject:controller];
//
[controller release];
}
// add the controller's view to the scroll view
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
NSLog(#"ScrollViewWithPagingViewContrller :: scrollViewDidScroll");
// We don't want a "feedback loop" between the UIPageControl and the scroll delegate in
// which a scroll event generated from the user hitting the page control triggers updates from
// the delegate method. We use a boolean to disable the delegate logic when the page control is used.
if (pageControlUsed) {
// do nothing - the scroll was initiated from the page control, not the user dragging
return;
}
// Switch the indicator when more than 50% of the previous/next page is visible
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor(scrollView.contentOffset.x - pageWidth / 2) / pageWidth;
pageControl.currentPage = page;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// A possible optimization would be to unload the views+controllers which are no longer visible
}
// At the begin of scroll dragging, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
NSLog(#"ScrollViewWithPagingViewContrller :: scrollViewWillBeginDragging");
pageControlUsed = NO;
}
// At the end of scroll animation, reset the boolean used when scrolls originate from the UIPageControl
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
NSLog(#"ScrollViewWithPagingViewContrller :: scrollViewDidEndDecelerating");
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender {
NSLog(#"ScrollViewWithPagingViewContrller :: changePage");
int page = pageControl.currentPage;
// load the visible page and the page on either side of it (to avoid flashes when the user starts scrolling)
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
// update the scroll view to the appropriate page
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
// Set the boolean used when scrolls originate from the UIPageControl. See scrollViewDidScroll: above.
pageControlUsed = YES;
}
I have implemented photo album view where in first view i have shown all the thumbnail images and on clicking each image it gives its full screen view. you also scroo the images.
See this answer.
All the best.
The answer is
scrollView1.contentOffset = CGPointMake( , );
quite simple. spent lot of time.