I have a FirstView loaded with tableView and when a accessory button of tableviewCell is tapped then it goes to SecondView.The data in SecondView is loaded from service url and so it takes time.So I need to show activityIndicator when accessorybutton is tapped, stop it after loading the whole data .BUt I couldnot see the activityindicator getting displayed.
This is the code Im working on :
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.color = [UIColor redColor];
[scrollView addSubView:activityIndicator];
[activityIndicator startAnimating];
activityIndicator.frame=CGRectMake(140, 195, 37, 37);
[activityIndicator startAnimating];
SecondView *secView = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
secView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
UITableViewCell* cell = [tableView cellForRowAtIndexPath:indexPath];
UILabel *name1 = (UILabel*)[cell viewWithTag:111];
secView.provName = [name1 text];
[self presentModalViewController: secView animated:NO];
[secView release];
}
Where I m going wrong?
EDIT:
SecondView:
-(void)viewWillAppear:(BOOL)animated
{
activityIndictr = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndictr.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
activityIndictr.color = [UIColor redColor];
[testscroll addSubview:activityIndictr];
[activityIndictr startAnimating];
}
-(void)viewDidLoad
{
[super viewDidLoad]
// I m calling many service urls(10) and assigning to labels and tableview
[activityIndictr stopAnimating];
}
You should call the activity indicator in the SecondView's ViewWillAppear , so that immediately after pushing in this view the activity indicator starts and then dismiss it when all the data is parsed from the url.
This is because the Second View Controller will be pushed almost immediately and the data will take time to load
You allocate two activity indicators, throw the first one away, then start animating the second one twice and never add any activity indicator into any existing view. No wonder it’s not showing up. Try [[secView view] addSubview:activityIndicator] or something similar.
Do this in viewWillAppear of SecondView :
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
Again I have updated the answer.
put this code in appdelegate And define static object in appdelegate like below
static UIActivityIndicatorView *activityView;
+(void)showActivityIndicator{
if (!activityView) {
activityView = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.center = CGPointMake(160, 230);
[activityView startAnimating];
UIWindow *win = [UIApplication sharedApplication].keyWindow;
[win addSubview:activityView];
}
}
+(void)removeActivityIndicator{
if ([activityView superview]) {
[activityView removeFromSuperview];
activityView = nil;
}
}
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
UIWindow *window = [UIApplication sharedApplication].keyWindow;
//global static activity indicator... you can access from any other view controlller
[AppDelegate showActivityIndicator];
}
And after getting response
[AppDelegate removeActivityIndicator];
Related
I am using AsyncImageView classes to apply lazy loading on UITableView. And want to apply activity indicator on image view until the image is loaded on cell. Below is my code i am trying.
// AsyncIamgeView.m
- (void)connectionDidFinishLoading:(NSURLConnection*)theConnection {
//[connection release];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
indicator.center = CGPointMake(15, 15);
connection=nil;
if ([[self subviews] count]>0) {
[[[self subviews] objectAtIndex:0] removeFromSuperview];
}
UIImage *imgData = [UIImage imageWithData:data];
UIImageView* imageView = [[UIImageView alloc]init];
[imageView addSubview:indicator];
[indicator startAnimating];
if(imgData == nil)
{
imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"NoImagenew.png"]];
//[indicator stopAnimating];
}
else{
imageView = [[UIImageView alloc] initWithImage:imgData];
// [indicator stopAnimating];
}
//imageView.contentMode = UIViewContentModeScaleAspectFit;
//imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth || UIViewAutoresizingFlexibleHeight );
//[imageView sizeToFit];
[self addSubview:imageView];
imageView.frame = self.bounds;
//imageView.frame = CGRectMake(0, 0, 85, 94);
[imageView setNeedsLayout];
[self setNeedsLayout];
//[data release];
data=nil;
}
// cellForRowAtIndexPath method.
asyncImageView = [[AsyncImageView alloc]initWithFrame:CGRectMake(1, 3, 85, 54)];
[asyncImageView loadImageFromURL:[NSURL URLWithString:imageUrlString]];
[cell.contentView addSubview:asyncImageView];
This code shows activity indicator but when image is loaded after that not before loading images. Please guide for above.
You have to create AsyncImageView object instead of UIImageView, then it will automatically add indicator to your view
AsyncImageView *imageView = [[AsyncImageView alloc] initWithFrame:CGRectMake(1, 3, 85, 54)];
[cell addSubview:imageView];
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:imageView];
//load the image
imageView.imageURL = [imageURLs objectAtIndex:indexPath.row];
Here is an example of this
Currently you are adding activity indicator when your image is downloaded.
Here is the simple idea, hope you can implement this in your code
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when your connection receives a response
// add your activity indication here and start animating
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// This method is called when your image is downloaded.
// remove your activity indicator or stop animating here
}
Hope u downloaded AsyncImageView from https://github.com/nicklockwood/AsyncImageView. By default, it has the feature to show activity indicator. You just dont need to add or remove any code by yourself to get this feature works. Just call loadImageWithURL.
I think u are using asynimageview classs, In that by default you will get the loader in the cell itself .
AysncImageView already has a loader.
You won't see it if your background is black since it loads the default activity indicator.
So, just set the activityIndicatorStyle property for your AsyncImageView object based on your background.
In my case, my background was black, so I used the following code :
asyncImgView.activityIndicatorStyle = UIActivityIndicatorViewStyleWhite;
I m trying out for the concept of UIActivityIndicator.In the firstView I have a tableView loaded with data and corresponding accessorybutttons.So when a accessorybutton of a tableViewCell is tapped then DetailsView is loaded.Meanwhile Im adding an activityIndicator when accessorybutton is tapped.
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicator.color = [UIColor blackColor];
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
activityIndicator.frame=CGRectMake(140, 195, 37, 37);
DetailsView *detailView= [[DetailsView alloc] initWithNibName:#"DetailsView" bundle:nil];
detailView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
UILabel *empid=(UILabel*)[cell viewWithTag:117];
detailView.Id=[empid text];
[self presentModalViewController: detailView animated:NO];
[detailView release];
}
Then in DetailsView based on the empid it received from firstView it loads some data
- (void)viewDidLoad
{
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicator.color = [UIColor blackColor];
[self.view addSubview:activityIndicator];
activityIndicator.frame=CGRectMake(140, 195, 37, 37);
////loads data from service url and parsing is done
[activityIndicator stopAnimating];
}
Until here it is working perfectly..I have a back button in DetailsView and whenever it is pressed presentmodalViewController is dismissed.
-(IBAction)btnBack
{
[self dismissModalViewControllerAnimated:NO];
}
But now the problem is I can see the presentmodalViewController getting dismissed but the activityindicator which started animating when accessorybutton is tapped still animating.So how do I stop that animating activityIndicator when presentView is dismissed and display only the data of prevoius view.
in ViewWillAppear method of first view write below code
[activityIndicator hidesWhenStopped];
tell me whether it is working or not!!!
Happy coding!!!!
Use following code
- (void) tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
{
detailView.Id=[empid text];
[activityIndicator stopAnimating];
[self presentModalViewController: detailView animated:NO];
}
or in your viewWillDisappear of FirstView
{
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperView];
}
in DetailsView class in viewDidLoad method just add activityIndicator as a subview and start animating like bellow..
- (void)viewDidLoad
{
activityIndicator = [[UIActivityIndicatorView alloc]initWithFrame:CGRectMake(143, 220, 37, 37)];
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
activityIndicator.color = [UIColor blackColor];
[self.view addSubview:activityIndicator];
activityIndicator.frame=CGRectMake(140, 195, 37, 37);
[activityIndicator startAnimating];
}
And also stopAnimating when your data download complete or fail and also in bellow method add in btnBack method or viewWillDisappear just add this bellow code
[activityIndicator stopAnimating];
[activityIndicator removeFromSuperview];///Add this line if you want to remove from superview
In the viewWillAppear of first view add [activityIndicator stopAnimating];
-(void)viewWillAppear:(BOOL)animated
{
if (activityIndicator)
{
[activityIndicator stopAnimating];
}
}
I am using a scrollview to display a viewcontrollers view. if the user reaches the end of the cached views my method reloads the new views. My NSLogs say that the method is finished but it takes additional 5 seconds to display the view.
I think that the [scrollView addSubview:vc.view] is very very slow but I found nothing to improve it.
the whole method gets called in -(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
scrollView.userInteractionEnabled = NO;
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[activityIndicator setFrame:CGRectMake((320.f*index)+135.f, 151, 50, 50)];
[activityIndicator setHidesWhenStopped:YES];
[activityIndicator startAnimating];
[scrollView addSubview:activityIndicator];
MBBAppDelegate *delegate = (MBBAppDelegate *)[UIApplication sharedApplication].delegate;
[delegate fetchDealsWithFilter:dealFilter fromIndex:index toIndex:(index+3) onSuccess:^(id object){
MBBDealList *list = object;
int i = 0;
ProductDetailViewController *vc;
for (MBBDeal *deal in [list deals]) {
NSLog(#"start %i",i);
int indexInArray = i;//[list.deals indexOfObject:deal];
if (indexInArray+index >= numDeals) {
return;
}
vc = [[ProductDetailViewController alloc] init];
//fetch the deal and insert
vc.numberOfDeals = numDeals;
vc.dealIndex = index+1+indexInArray;
vc.dealFilter = dealFilter;
vc.deal = deal;
vc.view.frame = CGRectMake(320.f*(index+indexInArray), 0.f, 320.f, 436.f);
[scrollView addSubview:vc.view];
[productDetailViewControllers insertObject:vc atIndex:(index+indexInArray)];
i++;
}
[activityIndicator stopAnimating];
scrollView.userInteractionEnabled = YES;
}];
}
Does anyone know how I can improve my method?
What I can understand from your problem is that, the activity indicator that you have used to show the data fetch process is not used properly.
You data fetch process is still working, even after the activity indicator disappears.
You can do 2 things for that:
ether call the data fetch method in background using performSelectorInBackground method or place the activity indicator in the app delegate where you have created your data fetch method.
I am implementing the searchdisplay controller on the iPhone App, but will hit the following error when I try to click on the search bar (after a few tries)
Thread 1: EXC_BAD_ACCESS (code=1, address=0x30000008)
Snippet of my code as follows:
- (void)viewDidLoad
{
//Setting up the search bar for search display controller
UISearchBar *tempBar = [[UISearchBar alloc]initWithFrame:CGRectMake(0, 34, 320, 44)];
self.sBar = tempBar;
[tempBar release];
self.sBar.delegate = self;
self.sBar.tintColor = [UIColor colorWithHexString:#"#b6c0c7"];
self.sBar.placeholder = #"Search DM friends";
self.searchDisplayController = [[[UISearchDisplayController alloc] initWithSearchBar:sBar contentsController:self]autorelease];
[self setSearchDisplayController:searchDisplayController];
[searchDisplayController setDelegate:self];
[searchDisplayController setSearchResultsDataSource:self];
self.searchDisplayController.searchResultsTableView.delegate = self;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView *headerView = [[[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 78)]autorelease];
headerView.backgroundColor = [UIColor colorWithHexString:#"#ebe7e6"];
if (tableView != self.searchDisplayController.searchResultsTableView){
//Search
UILabel *tagFriendsTitle = [[UILabel alloc]initWithFrame:CGRectMake(10, 10, 320, 16)];
tagFriendsTitle.font = [UIFont boldSystemFontOfSize:14];
tagFriendsTitle.backgroundColor = [UIColor clearColor];
tagFriendsTitle.text = #"Who should see this? Tag them!";
[headerView addSubview:tagFriendsTitle];
//THIS IS WHERE I GET MY EXC_BAD_ACCESS error
[headerView addSubview:self.sBar];
[tagFriendsTitle release];
}
return headerView;
}
I am not sure which part of my code is causing the error, but it seems that the sBar deallocated from memory when I try to add it to header subview? But I am not sure why I needed to click on the search bar multiple times before that happens.
This is how it looks on the iPhone, the searchbar forms part of the headerview
go to product>edit schems> enable nszombie objects and see what's the prblem there
If this is an assign property, you should probably change it to a retain property. And don't forget to set the property to nil in dealloc and viewDidUnload.
I want to get list from server it is taking some time So at that time I'm displaying progress indicator. My problem sometimes the progress indicator is appearing and some times it is not appearing. The code I used is
-(void)viewWillAppear:(BOOL)animated
{
[self loadprogressIndicator];
}
-(void)loadprogressIndicator
{
MessengerAppDelegate* appDelegate = (MessengerAppDelegate*) [ [UIApplication sharedApplication] delegate];
[appDelegate showWaitingView];
[NSThread detachNewThreadSelector:#selector(statusIndicatorForRefresh) toTarget:self withObject:nil];
}
-(void)statusIndicatorForRefresh
{
NSAutoreleasePool* pool=[[NSAutoreleasePool alloc]init];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[self performSelectorOnMainThread:#selector(loadList) withObject:nil waitUntilDone:NO];
[NSThread exit];
[pool release];
}
-(void)loadList
{
MessengerAppDelegate* appDelegate = (MessengerAppDelegate*) [ [UIApplication sharedApplication] delegate];
customerList = [appDelegate getCustomersArray];
[theTableView reloadData];
[appDelegate removeWaitingView];
}
And in appdelegate.m I implemeted these two methods
- (void)showWaitingView
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
CGRect frame = CGRectMake(90, 190, 32, 32);
UIActivityIndicatorView* progressInd = [[UIActivityIndicatorView alloc] initWithFrame:frame];
[progressInd startAnimating];
progressInd.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
frame = CGRectMake(130, 193, 140, 30);
UILabel *waitingLable = [[UILabel alloc] initWithFrame:frame];
waitingLable.text = #"Processing...";
waitingLable.textColor = [UIColor whiteColor];
waitingLable.font = [UIFont systemFontOfSize:20];
waitingLable.backgroundColor = [UIColor clearColor];
frame = [[UIScreen mainScreen] applicationFrame];
UIView *theView = [[UIView alloc] initWithFrame:frame];
theView.backgroundColor = [UIColor blackColor];
theView.alpha = 0.7;
theView.tag = 999;
[theView addSubview:progressInd];
[theView addSubview:waitingLable];
[progressInd release];
[waitingLable release];
[window addSubview:[theView autorelease]];
[window bringSubviewToFront:theView];
[pool drain];
}
- (void)removeWaitingView
{
UIView *v = [window viewWithTag:999];
if(v) [v removeFromSuperview];
}
Can anyone please help me. Happy Coding..
Thanks in advance.
Praveena..
You are doing all your activity on the main thread. Your app will appear to be blocked because you block the UI thread.
Also what is the use of launching an NSThread if all it does is call a method on your main thread and not even wait for it to complete? You are doing no multithreading at all.
Your app does this:
in main thread:
show waiting view
do 1 run loop cycle
do your data processing
hide waiting view
since your data processing is in the main thread you block everything there. You should do the processing in a secondary thread and leave the main thread for UI handling.