For the iPhone 5.0 I am getting lot of image(image url's) and text data from server in a json form. My requirement is to load the first five images from the server and when the user scrolls down the next five images load and so on. I need to show it in a UITableViewCell. By doing this I can reduce the network calls and make the application faster on the device.
Currently, I am using a background thread to load images, but they continuously load in the background. I don't want to do it like this.
Check this sample code from Apple.
It should answer your question.
LazyTableImages
it uses UIScrollViewDelegate to implement the following function
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
[self loadImagesForOnscreenRows];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[self loadImagesForOnscreenRows];
}
Basically it does what you want - just load image of the visible cell.
With [self.tableView indexPathsForVisibleRows] you can call the startIconDownload function to the specified tableCell
Related
I'm working on retreiving images from server and display it in ios.I select the image that I need to see on full screen it comes. But the problem is, once I go back, it reloads the whole images again from server. Are there any solution so as to save it in cache file for a while. I searched the whole internet for this, but didn't get a proper solution. Can any one please specify best tutorial for that. I'm newbie to ios
If each time you go back it reloads all the images agin from the server is probably because you may either create a new view or because you are calling to load the images from the method viewWillAppear instead of in the viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
// Load the images here...
}
Instead of in here:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
If this doesn't not help, please provide us with some code.
I feel as though there is a really simple solution to my problem, but thus far I have had little success... I want to load my initial .xib file (exiting the default.png splash screen early), so that I may display an activity indicator while loading my html data and setting the text label fields created by my xib file.
Unfortunately, when I execute the following code below, I display my default.png image until all of the data is loaded from each website... What may I change in order to first display my mainView, then start the activity indicator, load my html data, and set the text labels in my mainView?
#implementation MainViewController
- (void)viewDidLoad {
[super viewDidLoad];
[activityIndicator startAnimating];
[self runTimer];
}
- (void)viewDidAppearBOOL)animated {
[super viewDidAppear:animated];
[self loadHTMLData1];
[self loadHTMLData2];
[self loadHTMLData3];
[self loadHTMLData4];
[activityIndicator stopAnimating];
}
...
It's all to do with how iOS updates the ui. When you call
[activityIndicator startAnimating];
it doesn't mean start animating immediately, it means you're telling the ui the next time you are updating the display, start animating.
All of this updating happens on the main thread (if you haven't made a thread, you're already on the main thread) so if you do something else that takes a long time, it will do this before updating the display.
There are a few ways to fix this and they all involve making another thread that runs in the background.
Take a look at NSOperation (and NSOperationQueue) - this will let you queue up individual tasks that iOS will run in the background for you. then when they are complete you can update your display again and turn off your activity indicator.
There's NSOperationQueue tutorials all over google :)
Hope that helps.
I am trying to create a small game for the iPhone with images and I want to them to zoom in when the player is pinching on the screen. I have seen the tutorials with one UIImageView. However, now that I am using multiple UIImageViews, things do not work OK.
I put them in an UIView and I am trying to zoom the UIView. However things are not scaling inside the screen when I run the simulator.
I use the following code
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return containerView; //containerView is the UIView containing all the UIIMageviews
}
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
{
[containerView setTransform:CGAffineTransformIdentity];
containerView.contentScaleFactor = scale;
}
Any suggestions?
Thanx!
Have a look at the ScrollViewSuite sample on the apple developer site, that has a working example of what I think you're trying to do.
(I think I got the name right, the developer site is down for updates just now so I can't give you a link.)
I have a UIScrollView that contains large images and am using paging to scroll between images. In order to save memory, I am loading only one image before and after the currently visible one and loading/releasing new images after a scroll has completed.
The problem occurs when one scrolls quickly and scrollViewDidEndDecelerating is not called.
How can I detect continuous scrolling?
I could check item location on every scrollViewDidScroll but this seems a bit heavy...
Perhaps a table view with custom cell content would work better for you, since it has a lot of logic built in for only loading cells that are visible as opposed to everything at once. There are lots of tutorials for how to manage table views in various ways.
My temporary solution is to cancel continuous scrolling by disabling scroll from when the user lifts the finger until scroll has completed.
-(void) scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
[scrollView setScrollEnabled:NO];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
[scrollView setScrollEnabled:YES];
}
if you are still looking for a solution... this what I do, it works really good having a good performance, too.
- (void)scrollViewDidEndDragging:(UIScrollView *)sv willDecelerate:(BOOL)decelerate
{
if (!decelerate)
{
// load images and unload the ones that are not needed anymore
[self someMethod]
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)sv
{
// load images and unload the ones that are not needed anymore
[self someMethod]
}
You have to check both scrollViewDidEndDecelerating and scrollViewDidScroll.
When to user swipes and releases it letting to have the "momentum" scroll the first will be called at the and. If the user decides to stop the scroll with his finger by tapping to the tableview (or scroll comes to the most bottom, but I am not sure about that) the second event is fired.
You can do something like this
-(void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 1.5) / pageWidth) + 1;
}
this method is called anytime the contentoffset changed whether programmatically or not.
From this method you can check to see if 'page' is the same as your current page, if not, you know you need to load something. The trick here is making images load without holding up the scrolling of the scrollview. That is where I am stuck.
the page calculation will change to next/previous when you are half way to the next page
As per my experience, #jd291 is correct; I am using following callbacks successfully for most places
-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
but, the only case when a callback is not called is that you may not had set up the delegate properly.
The WWDC 2010 has talked about this. They do a reuse of the sub scrollviews, alloc the missing image view in scrollViewDidScroll:. The video may help:
Session 104 - Designing Apps with Scroll Views
I'm having a really hard time understanding delegates and object inheritance (if I may use this word) and I think I need a simple (or so I think) thing: catch scrollViewDidScroll event in UIWebView and get offset (basically, just to know if scroll is not on top/bottom, so I could hide navigation and tab bars).
Is there any way I could do it? I already using UIWebviewDelegate in my view controller to "shouldStartLoadWithRequest". Maybe I could some how use UIScrollViewDelegate too for scrollViewDidScroll? If yes, then how?
I really have trouble understanding delegates. I've red some articles, but still, in practice, I can't manage to use them.
Any help or info would be lovely.
Thank you in advance!
To retrieve scroll events on UIWebView I personnaly use this code to get the scrollview that is inside the UIWebView :
- (void) addScrollViewListener
{
UIScrollView* currentScrollView;
for (UIView* subView in self.myWebView.subviews) {
if ([subView isKindOfClass:[UIScrollView class]]) {
currentScrollView = (UIScrollView*)subView;
currentScrollView.delegate = self;
}
}
}
It's working. You can also use it to call [currentScrollView setContentOffset:offSet animated:YES]; The only problem may be not to pass Apple code checking. I don't know yet since I'm still in coding phase.
[UPDATE] The app with this code is in the app store for 4 months now and used by 40 000 users. I didn't have any trouble [UPDATE]
You can use the following methods to solve your problem.
For getting the pageOffset:
int pageYOffset = [[webViewObj stringByEvaluatingJavaScriptFromString:#"window.pageYOffset"] intValue];
For getting the total scroll height of a webpage:
int scrollHeight = [[webViewObj stringByEvaluatingJavaScriptFromString:#"document.documentElement.scrollHeight"] intValue];
For scrolling the webpage to a particular offset:
[webViewObj stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"document.body.scrollTop = %d",scrollHeight ]];
I made a modification to detect the class with isKindOfClass. Works - but may have issues with Apple code checking as stated above.
UIScrollView* currentScrollView;
for (UIView* subView in terms.subviews) {
if ([subView isKindOfClass:[UIScrollView class]]) {
NSLog(#"found scroll view");
currentScrollView = (UIScrollView *)subView;
currentScrollView.delegate = self;
}
}
Old thread, I know -
As of iOS 5.0 you can use
myAccountWebView.scrollview
to access content size and offset.
There is a scrolling view in the UIWebView, but it a) isn't a UIScrollView, and b) is something Apple considers a private implementation detail (and you should too). I only really have two suggestions:
File a bug with Apple asking them to expose more of the infrastructure of the web view, or at least add some more delegate methods by which we can be notified of these sorts of events.
Add some JavaScript code to your page that listens from scroll events, and notifies your app of them.
The basic foundation of #2 is to load a fake URL, and have your web view delegate process (and abort!) that load. (This question has come up a few times here on Stack Overflow.)
UPDATE:
As of iOS 5, there is now a public scrollView property on UIWebView that you can use to customize scrolling behavior. The exact view hierarchy of the web view remains an undocumented implementation detail, but this gives you a sanctioned way to access this piece of it.
It's a good question. UIWebView is not a subclass of UIScrollView, although I can see why one might think it is. That means using the UIScrollViewDelegate methods is not an option to do what you want, and the UIWebViewDelegate protocol does not respond to those scrolling event type of messages. I don't think there's an easy way to detect scrolling events in a web view.
I tired the delegate method and found it prevented the view from scrolling when the keyboard was shown. I found that by adding an observer you do not override the current delegate and will prevent you from effecting the webview performance.
for (UIView* subView in myAccountWebView.subviews) {
if ([subView isKindOfClass:[UIScrollView class]])
{
NSLog(#"found scroll view");
[((UIScrollView*)subView) addObserver:self forKeyPath:#"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}
}