I have this problem where I am adding an UIActivityIndicatorView to a UIScrollView; Everything is working fine, except it does not start spinning unless the UIScrollView is scrolled.
Can anyone help me with this issue?
Thank you.
here is some code:
UIActivityIndicatorView *loaderActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loaderActivity.center = CGPointMake(87/2,y+56/2);
loaderActivity.tag=tag;
[mainScrollView addSubview:loaderActivity];
[loaderActivity startAnimating];
[loaderActivity release];
You need to call startAnimating on the activity indicator to have it animate. Alternatively in interface builder you can tick the "animating" tickbox.
The fact that it's not animating until you scroll in the scroll view is a symptom that your call to startAnimating is happening in a background thread. UIKit calls should be made in the main thread.
You can verify that it's happening in a background thread by adding code like this:
if ([NSThread isMainThread]) {
NSLog(#"Running on main thread.");
} else {
NSLog(#"Running on background thread.");
}
You'll want to make sure all of the code you showed in your question is running on the main thread. To do this, you can change your code to look something like this:
// this code would be wherever your existing code was
[self performSelectorOnMainThread:#selector(addActivityIndicatorToView:) withObject:mainScrollView waitUntilDone:YES];
// this would be a new method in the same class that your existing code is in
- (void) addActivityIndicatorToView:(UIView*) view {
UIActivityIndicatorView *loaderActivity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
loaderActivity.center = CGPointMake(87/2,y+56/2);
loaderActivity.tag=tag;
[view addSubview:loaderActivity];
[loaderActivity startAnimating];
[loaderActivity release];
}
activityIndicator = [[UIActivityIndicatorView alloc]
initWithFrame:CGRectMake(87/2,y+56/2);
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.tag=tag;
[mainScrollView addSubview:loaderActivity];
[activityIndicator startAnimating];
[activityIndicator release];
Had an issue where I made the startAnimating call in the viewDidLoad and didn't work. I moved the call in the viewWillAppear and it worked!
Try running the animator in a different thread.
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:#selector(showProgress) object:nil];
[thread start];
//do whatever your want here
//call this when you want it stop animating
[activityIndicator stopAnimating];
[thread release];
- (void)showProgress{
[activityIndicator startAnimating];
}
Related
In .h file:
UIActivityIndicatorView *mySpinner;
In viewDidLoad:
mySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
mySpinner.center = CGPointMake(160, 240);
mySpinner.hidesWhenStopped = YES;
[self.view addSubview:mySpinner];
and finally I am calling it on button click as:
[mySpinner startAnimating];
The problem is that when I called it in viewDidLoad it showed and start animating but didn't animate on button click not even show. Help me on this issue.
Thanks in advance
I'm guessing your 'mySpinner" ivar isn't being properly retained or declared.
In your .h file, declare it as a property. That is:
#property (strong) UIActivityIndicatorView *mySpinner;
then, when you create it:
self.mySpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
and when you reference it in your button click method:
[self.mySpinner startAnimating];
Thanks to everyOne who helped me ….
I have resolved the issue and here i am posting the answer for some one who is in search of this… actually the issue is "i am Downloading some records on synchronous request. So thats why UI Updation is blocked for a while.
so this is creating problem here….
On Button click i just make a new thread that call a method 'start'
[NSThread detachNewThreadSelector: #selector(Start) toTarget:self withObject:nil];
and the 'start' method is
- (void) Start
{
Spinner.hidden = NO;
[mySpinner startAnimating];
}
I have a view which is created in IB. inside it I have a scroll view created programmatically. Within the scroll view I connect to a web service and fetch the content and the image. I want to show an activity indicator while doing this. So I have:
- (void)viewDidLoad
{
[super viewDidLoad];
activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.frame = CGRectMake(0.0, 0.0, 40.0, 40.0);
activityIndicator.center = self.view.center;
[self.view.window addSubview:activityIndicator];
And right after the scrollview is added, I have:
[self.view addSubview:scrollView];
// ADD Scroll View Ends
//Add the Lisitng Image
NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(loadImage)
object:nil];
[queue addOperation:operation];
And in loadimage I have:
- (void)loadImage {
[activityIndicator startAnimating];
I've tried [self.view.window addSubview:activityIndicator];, [self->ScrollView addSubview:activityIndicator];, [self.view addSubview:activityIndicator];
but I just can't get the indicator to show. Anyone have any idea what might be wrong?
You should do this in you viewDidload
- (void)viewDidLoad
{
//Start Activity Indicator View
indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicatorView.frame = CGRectMake(40.0, 20.0, 60.0, 60.0);
indicatorView.center = self.view.center;
[self.view addSubview:indicatorView];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[indicatorView startAnimating];
[self performSelectorInBackground:#selector(loadscroll) withObject:self];
}
Note: "performSelectorInBackground" will show you an activity indicator on the view and your loadScroll method will fetch all data from internet and do other work.
-(void)loadscroll
{
//Your Scroll View
//Your other Data Manipulation even from internet
//When data is fetched display it
[self removeActivityIndicator]; //To stop activity Indicator
}
- (void)removeActivityIndicator
{
[indicatorView stopAnimating];
}
What I have found so far after multiple times facing above problem with activity indicator.
Activity indicator and the function (or method or piece of code) that is required to be executed after appearance of activity indicator both can't run on main thread. If it is so activity indicator will not appear. The solution is to run activity indicator on main thread and the function in a background thread.
I have also faced a case in which the function followed by activity indicator can't run in a background thread. In my case it was playing a music file using MPMoviePlayerController that can't be executed in a background thread. What I did to solve this issue was to run activity indicator in the main thread and then used an NSTimer to call my method after a delay that was good enough for activity indicator to appear and start animating.
I have also found that activity indicator must be called in performSelectorOnMainThread and should be added as a subview on the top view of given viewController once it starts animating.
Once it is not needed it should be removed by calling removeFromSuperView method.
In loadDidLoad controller call method with thread, like that:
- (void)viewDidLoad {
[super viewDidLoad];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(loadImages) object:nil];
[self.operationQueue addOperation:operation];
[operation release];
}
loadImages method downloading image and show it:
- (void) loadImages {
#synchronized (self) {
// download image...
// ...
// and next:
UIImageView *imageView = [imageViews objectAtIndex:currentImageIndex];
[imageView performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:YES];
[imageView performSelectorOnMainThread:#selector(setImage:) withObject:[UIImage imageWithData:imageData] waitUntilDone:YES];
}
//...
}
that work if show view first time, next time i must rotate iphone to show images.
why view doesn't redraw?
i tried this code according to advices:
// imageButton is a UIView with button, image and label
NSData *imageData = [[HttpClient sharedInstance] getResourceWithCache:thumbPath];
[imageButton performSelectorOnMainThread:#selector(setImage:) withObject:[UIImage imageWithData:imageData] waitUntilDone:YES];
[imageButton performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:YES];
[imageButton drawRect:imageButton.frame];
but do not work.
your problem is in the line
[imageView performSelectorOnMainThread:#selector(setNeedsDisplay) withObject:nil waitUntilDone:YES];
You would need to call setNeedsDisplay in self.view and not on self, as thats a method for UIView and not UIViewController.
Double check this by subclassing your view and putting a break point in drawRect: , as setNeedsDisplay must call drawRect.
I'm assuming that loadDidLoad is a typo, and that you meant viewDidLoad.
The viewDidLoad method is called when the view controller is done loading. It only does this once, unless the app receives a memory warning and the view controller gets unloaded.
If you're retaining the view controller and later showing the same view controller object again, the viewDidLoad method does not get called again.
If you need to perform an action every time the view controller gets pushed onto the view stack, you can use viewWillAppear: or viewDidAppear:.
I've added the ELCimagepicker (https://github.com/Fingertips/ELCImagePickerController) to my project and it works perfectly, allowing the user to select multiple images for a slideshow. But when you click 'Save', there can be a lengthy delay depending on how many photos were added.
I've been trying to add a UIActivityIndicator when the user clicks 'Save', but having trouble due to the modal view that is presented. I can call a method from the activity that ELCimagepicker presents (ELCImagePickerController) and this gets actioned by the activity handling the presenting of the image picker. But whenever I try to add to the view, it isn't shown as the modal is on top of the activity indicator.
I've tried using bringSubviewToFront, I've tried adding the code directly to the imagepicker method file with [[self parentViewController] addSubView], but no luck.
Here's the latest code I tried: (indicator is declared in the .h file as UIActivityIndicator *indicator)
indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
indicator.hidden=false;
[self.navigationController.view addSubview:self.indicator];
[self.navigationController.view bringSubviewToFront:self.indicator];
[indicator startAnimating];
if([delegate respondsToSelector:#selector(elcImagePickerController:showIndicator:)]) {
[delegate performSelector:#selector(elcImagePickerController:showIndicator:) withObject:self withObject:#"test"];
}
Has anyone had any success with adding a UIActivityIndicator on top of the ELCimagepicker, or another modal view handled by another class?
I've tried MBProgressHUD but couldn't get that working quite right either - it would show up when I used it in the ELCimagepicker class, but crashed on removal with:
bool _WebTryThreadLock(bool), 0x42368e0: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...
Any help would be fantastic.
Thanks.
I have figure out your problem. You can do this as below..
-(void)selectedAssets:(NSArray*)_assets {
UIActivityIndicatorView * activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
UIViewController * topView = [self.viewControllers objectAtIndex:[self.viewControllers count]-1];
activityIndicator.center = CGPointMake(topView.view.frame.size.width/2, topView.view.frame.size.height/2);
[activityIndicator setHidden:NO];
[topView.view addSubview:activityIndicator];
[topView.view bringSubviewToFront:activityIndicator];
[activityIndicator startAnimating];
[self performSelector:#selector(doProcess:) withObject:_assets afterDelay:2.1];
}
- (void) doProcess:(NSArray *)_assets {
NSMutableArray *returnArray = [[[NSMutableArray alloc] init] autorelease];
for(ALAsset *asset in _assets) {
NSMutableDictionary *workingDictionary = [[NSMutableDictionary alloc] init];
[workingDictionary setObject:[asset valueForProperty:ALAssetPropertyType] forKey:#"UIImagePickerControllerMediaType"];
[workingDictionary setObject:[UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]] forKey:#"UIImagePickerControllerOriginalImage"];
[workingDictionary setObject:[[asset valueForProperty:ALAssetPropertyURLs] valueForKey:[[[asset valueForProperty:ALAssetPropertyURLs] allKeys] objectAtIndex:0]] forKey:#"UIImagePickerControllerReferenceURL"];
[returnArray addObject:workingDictionary];
[workingDictionary release];
}
[self popToRootViewControllerAnimated:NO];
[[self parentViewController] dismissModalViewControllerAnimated:YES];
if([delegate respondsToSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:)]) {
[delegate performSelector:#selector(elcImagePickerController:didFinishPickingMediaWithInfo:) withObject:self withObject:[NSArray arrayWithArray:returnArray]];
}
}
Let me know if this answer help you ...
Thanks,
MinuMaster
It looks like you are updating UI on a background thread. All UIKit updates are to be done in the main thread. So I recommend you execute methods doing UI updates using performSelectorOnMainThread:withObject:.
I solved the issue like this
activityIndicatorObject = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
// Set Center Position for ActivityIndicator
activityIndicatorObject.center = CGPointMake(150, 250);
activityIndicatorObject.backgroundColor=[UIColor grayColor];
// Add ActivityIndicator to your view
[self.view addSubview:activityIndicatorObject];
activityIndicatorObject.hidesWhenStopped=NO;
[activityIndicatorObject startAnimating];
I'm using two threads in an iPhone app for the first time and I've run into a problem. In this prototype, I have a view controller that loads a local web page. I want an activity indicator to show until the page has finished loading. With the code below, the activity indicator starts, the page loads properly, but the activity indicator does not stop or hide. It doesn't look like the "loading" function ever gets called.
What am I doing wrong?
- (void)viewDidLoad {
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
[NSThread detachNewThreadSelector:#selector(getData) toTarget:self withObject:nil];
[super viewDidLoad];
}
- (void)getData {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[detailWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"page1" ofType:#"html"]isDirectory:NO]]];
[NSTimer scheduledTimerWithTimeInterval: (1.0/2.0) target:self selector:#selector(loading) userInfo:nil repeats:YES];
[pool release];
}
- (void)loading {
if(!detailWebView.loading){
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];
}
There's an easier way to do this without creating your own thread.
- (void)viewDidLoad {
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
[detailWebView setDelegate:self];
[detailWebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"page1" ofType:#"html"]isDirectory:NO]]];
[super viewDidLoad];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
}
You 'd betetr stop the activity indicator in the webview delegate method :
-(void)webViewDidFinishLoad:(UIWebView*)webView
Have you added debug output to loading to whether it gets called ? The code sure looks like that, it should get called after 0.5 seconds and I'd guess that detailWebView is still loading then.
Also, GUI stuff should be run on the main thread, so you may need to do:
- (void)loading {
if(!detailWebView.loading){
[activityIndicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
[activityIndicator performSelectorOnMainThread:#selector(removeFromSuperView) withObject:nil waitUntilDone:YES];
}
}
You're using a webview, which already provides a mechanism to know when a load has finished, and already loads data asynchronously - the use of a custom thread really isn't needed.
Register your object as the UIWebView's delegate. Call loadRequest on the UIWebView and start animating the progress indicator. Stop animating the progress indicator in:
-(void)webViewDidFinishLoad:(UIWebView*)webView
This method is defined by the UIWebViewDelegate protocol - make sure your object implements this protocol. You implement this method:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[activityIndicator stopAnimating];
}
http://developer.apple.com/iphone/library/documentation/uikit/reference/UIWebViewDelegate_Protocol/Reference/Reference.html