I load a RSS feed into a TableView. Before it is loaded, it displays a empty tableview.
Can I let a activity indicator show until it is loaded?
Current code looks like this :
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
[self.view addSubview:self.activityIndicator];
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
[view addSubview:self.activityIndicator];
self.tableView.tableHeaderView = view;
dispatch_sync(dispatch_get_main_queue(), ^
{
[self.tableView reloadData];
//Remove load feedback
});
}
This code doesn't show anything I don't know why I expected to have a loading animation at the top but instead a empty space is added at the top of the tableview
The code you've presented puzzles me a bit. I think what you should do is present the activity indicator in the parserDidStartDocument method and remove it in parserDidEndDocument. I suggest creating another UIView property, name it activityIndicatorView, and do something like this:
- (void)parserDidStartDocument:(NSXMLParser *)parser {
if (!self.activityIndicatorView) {
self.activityIndicatorView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.tableView.frame.size.width, 60)];
self.activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:(UIActivityIndicatorViewStyleGray)];
self.activityIndicator.center = CGPointMake(self.activityIndicatorView.frame.size.width/2,self.activityIndicatorView.frame.size.height/2);
[self.activityIndicatorView addSubview:self.activityIndicator];
}
self.tableView.tableHeaderView = self.activityIndicatorView;
[self.activityIndicator startAnimating];
}
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
[self.tableView reloadData];
[self.activityIndicator stopAnimating];
self.tableView.tableHeaderView = nil;
}
I don't know what your project looks like, but I assume you're doing something with the parsed document before reloading the table.
For this just add MBProgressHUD.h and MBProgressHUD.m into your project. Now to show indecator just write:
[MBProgressHUD showHUDAddedTo:self.view.window animated:YES];
and to hide write:
[MBProgressHUD hideAllHUDsForView:self.view.window animated:YES];
you can get classes from here
Related
When I bring up a UIImagePickerController and then close it, it duplicates the content in my modal window. Below are the before and after pictures:
Here's the code that shows the image picker:
-(void) choosePhotos
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
[imagePicker setDelegate:self];
[imagePicker setAllowsEditing:YES];
[imagePicker setSourceType:UIImagePickerControllerSourceTypeCamera];
[self presentViewController:imagePicker animated:YES completion:nil];
}
Here's the rest of my code (if needed):
-(id) init
{
self = [super init];
if (self)
{
[self.navigationItem setTitle:#"Deposit"];
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel" style:UIBarButtonItemStyleDone target:self action:#selector(cancel)];
[self.navigationItem setLeftBarButtonItem:closeButton];
toItems = #[#"Account...5544", #"Account...5567"];
UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[self.view addGestureRecognizer:recognizer];
}
return self;
}
-(void) hideKeyboard
{
for (UITextField *field in [scrollView subviews])
{
[field resignFirstResponder];
}
}
-(void) cancel
{
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [toItems count];
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [toItems objectAtIndex:row];
}
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[self.view setBackgroundColor:[UIColor whiteColor]];
UILabel *toLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 0, 50, 100)];
[toLabel setText:#"To:"];
toPicker = [[UIPickerView alloc] initWithFrame:CGRectMake(130, -30, 220, 100)];
[toPicker setDataSource:self];
[toPicker setDelegate:self];
UILabel *amountLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 100, 70, 100)];
amountLabel.lineBreakMode = NSLineBreakByWordWrapping;
amountLabel.numberOfLines = 0;
[amountLabel setText:#"Check Amount:"];
UITextField *amountField = [[UITextField alloc] initWithFrame:CGRectMake(130, 100, 270, 100)];
[amountField setPlaceholder:#"Enter Amount"];
[amountField setReturnKeyType:UIReturnKeyDone];
[amountField setKeyboardType:UIKeyboardTypeDecimalPad];
UILabel *imagesLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 200, 70, 100)];
imagesLabel.lineBreakMode = NSLineBreakByWordWrapping;
imagesLabel.numberOfLines = 0;
[imagesLabel setText:#"Check Images:"];
UIButton *imagesButton = [[UIButton alloc] initWithFrame:CGRectMake(120, 200, 244, 99)];
[imagesButton setBackgroundImage:[UIImage imageNamed:#"photos.png"] forState:UIControlStateNormal];
[imagesButton addTarget:self action:#selector(choosePhotos) forControlEvents:UIControlEventTouchUpInside];
CGRect bounds = [[UIScreen mainScreen] bounds];
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height)];
[scrollView setAlwaysBounceVertical:YES];
[scrollView setShowsVerticalScrollIndicator:YES];
[scrollView addSubview:toLabel];
[scrollView addSubview:toPicker];
[scrollView addSubview:amountLabel];
[scrollView addSubview:amountField];
[scrollView addSubview:imagesLabel];
[scrollView addSubview:imagesButton];
[self.view addSubview:scrollView];
}
I recommend you use viewDidLoad as the place to create and add your views:
- (void)viewDidLoad {
[super viewDidLoad];
//init and add your views here
//example view
self.someLabel = [[UILabel alloc] init];
self.someLabel.text = #"someExampleText";
[self.view addSubview:self.someLabel];
}
And either viewWillAppear or viewDidLayoutSubviews as the place to configure their sizes (i prefer viewDidLayoutSubviews so i'll use it as an example):
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
self.someLabel.frame = CGRectMake(kMargin,kMargin,kLabelWidth,kLabelHeight);
}
Of course, in order to do this you need to have a reference to all the views you wish to configure this way by creating a property to them in the interface:
#interface YourViewController ()
#property (nonatomic, strong) UILabel *someLabel;
#end;
static CGFloat const kMargin = 20.0f;
static CGFloat const kLabelHeight = 30.0f;
static CGFloat const kLabelWidth = 100.0f;
Also, it is recommended you avoid using hard coded values for their sizes (doing it like CGRectMake(20,20,100,70) but this it not completely wrong.
Not using hard coded values does not mean setting them yourself, it just means to make their values more readable (and on most cases, dynamic).
In my example, i created kMargin, kLabelHeight and kLabelWidth, meaning that anyone who looks at this code will understand what they mean, they will know what to change if needed, and these values can be used in other places.
For example, you could have 4 labels, and in order to keep them all following the same layout rules, all of them will use the kMargin value on the origin.x.
You could also, instead of using a static value for the width, you can implement a dynamic value, like this:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat labelWidth = self.view.bounds.size.width - (kMargin * 2);
self.someLabel.frame = CGRectMake(kMargin,kMargin,labelWidth,kLabelHeight);
}
What i did here is to make my label to have the same width as my super view, but i made it account for the left and the right margins (by taking the total view width and reducing twice the margin value).
Since we are doing this on the viewDidLayoutSubviews method, which gets called whenever the superview changes its size (for example, orientation change) this will ensure your UILabel can be shown on any size of view and orientation without extra code to handle 'specific cases'.
Your UI elements are being added to your view every time viewWillAppear is called. This is called when your image picker dismisses and returns to your view, so they're being duplicated. Either check to see whether your UI elements already exist before creating them again, or do your UI setup in the viewDidLoad method which will only be run once. You could try this perhaps, using a BOOL property to keep track:
-(void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
if (!self.alreadyAppeared) {
self.alreadyAppeared = YES;
// Create labels and buttons
}
}
I am developing one iPad application using story board.In my view controller one table is set as the left side and one more view is set as the right side.I need to set one activity controller above the right side view.Which need to start animating when i click the right side table cell and need to stop after 1s.I am using 'didSelectRowAtIndexPath' function for select table cell.How i will set activity indicator for my situation.
In didSelectRowAtIndexPath method you could make a call to below function:-
-(void)setActivityIndcator:(UIView *)view
{
transparentView = [[UIView alloc] init];
transparentView.frame = view.frame; //Provide frame of right side view.
transparentView.alpha = 0.5; //To provide transparent look and feel.
activityInd = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityInd.frame = CGRectMake(transparentView.frame.size.width/2, transparentView.frame.size.height/2, 50, 50); //Change as you want it to be
[transparentView addSubview:activityInd];
[activityInd startAnimating];
[self performSelector:#selector(stopIndicator) withObject:self afterDelay:1];
}
-(void)stopIndicator //This method will be called after delay and would remove view and activityInd
{
[activityInd stopAnimating];
[activityInd removeFromSuperview];
[transparentView removeFromSuperview];
}
Also you could create a subclass of it and use it in any viewcontroller by creating it's object. That why u don't need to write down all function everytime.
use this in this method
didSelectRowAtIndexPath
UIActivityIndicatorView *activityView =
[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityView.frame = CGRectMake(120, 230, 50, 50);
[self.view addSubview:activityView];
Use the delegate method didSelectRowAtIndexPath of TableView and write the following code into it
UIActivityIndicatorView *activity =
[[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activity.frame = CGRectMake(self.view.frame.size.width/2, self.view.frame.size.height/2, 50, 50);
[self.view addSubview:activity];
[activity startAnimating];
Stope this when your work is done and remove it from the view
I am a beginner in iOS programming. I am creating a tableview where, on click of each cell a different xml gets parsed. I want to show a activity indicator when xml is parsing and stop that indicator when parsing is finished. my code is,
//Activity Indicator
//in viewDidLoad,
activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
activityIndicator.frame = CGRectMake(0.0, 0.0, 20.0, 20.0);
activityIndicator.backgroundColor=[UIColor colorWithRed:0/255.0f green:0/255.0f blue:0/255.0f alpha:0.5];
activityIndicator.center=self.view.center;
[activityIndicator startAnimating];
[self.view addSubview:activityIndicator];
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
cell = [tableView cellForRowAtIndexPath:indexPath];
if(cell.accessoryView==nil)
{
NSLog(#"index path is %i",indexPath.row+1);
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"cell_selected.png"]];
[myObj1 changecheckedvalue:1 forindex:[[tempArr objectAtIndex:indexPath.row]mainID]];
if (indexPath.row==0)
{
flagToCheck=1;
xmlName=#"Pournima";
[parseArray removeAllObjects];
[self xmlParsing];
}
}
}
How to achieve that? Please help.
You can use MBProgressHUD to display an activity view that sits on top the current view. The library is quite easy to use and implement. You would just import MBProgressHUD.h, and then call this method:
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
or if you want to show an activity view inside cell, maybe next to title, you could use something like,
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[cell.imageView addSubview:activityView];
[activityView startAnimating];
you would then remove the activityView from its superview when you are done.
Try using this one : https://github.com/jdg/MBProgressHUD
It has a better look and feel.
Start the activity indicator before calling the method for parsing in "didSelectRowAtIndexPath" and stop it at the end of the method for parsing.
I have an app with a table view controller in which a user selects a US state, a web service is called and data is displayed for that state in the destination table view controller. Since the web service can take some time to complete I want an activity indicator. Since there will be no temporary data to display, I need this to be processed synchronously. So my task is pretty simple: start the activity indicator, call the web service, and after it completes, stop the activity indicator.
I am obviously doing something wrong and no activity indicator ever displays.
Here is the code from my destination table view controller's viewDidAppear method:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
[self.tableView reloadData];
[spinner stopAnimating];
}
Header:
#property (strong, nonatomic) UIActivityIndicatorView *spinner;
GaugeList is the object which makes the web service call.
Can someone tell me how to get an activity indicator view to appear? Thanks!
You forgot to add spinner on table view. Your code should look as follows:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spiner.center = //set some center
[self.tableView addSubview: spinner];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
[self.tableView reloadData];
[spinner stopAnimating];
}
Also you send requests to a web service in main thread. This is bad practice. I would suggest something like following:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
spiner.center = //set some center
[self.tableView addSubview: spinner];
[self.tableView bringSubviewToFront:spinner];
spinner.hidesWhenStopped = YES;
spinner.hidden = NO;
[spinner startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
stateGauges = [[GaugeList alloc] initWithStateIdentifier:stateIdentifier andType:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[spinner stopAnimating];
});
});
}
At first you should add activity indicator to some view to show it. But you can not add it to UITableView, because UITableView is subclass of UIScrollView and you will see floating activity indicator. The best way in your case is to add activity indicator to navigation bar, etc. Or if you want to disable table view you should write something like this:
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
UIView *dummyView = [[UIView alloc] init];
dummyView.frame = self.tableView.bounds;
dummyView.alpha = 0.5f;
dummyView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
dummyView.userInteractionEnabled = YES;
dummyView.backgroundColor = [UIColor blackColor];
[dummyView addSubview:activityIndicator];
activityIndicator.center = dummyView.center;
[self.tableView addSubview:dummyView];
}
Try using self.spinner instead of using spinner.
I have many view controller when i click on tableView cell it move to new view controller problem is that it takes alot of time to move to the next view may be due to view which is to load fetches data from server here is my code for the view which loads
- (void)viewDidLoad {
appDelegate = (MultipleDetailViewsWithNavigatorAppDelegate *)[[UIApplication sharedApplication] delegate];
UIImageView *bottomImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Nav.png"]];
[bottomImageView setFrame:CGRectMake(0,690,1024,34)];
[self.view addSubview:bottomImageView];
UIButton *button1=[UIButton buttonWithType:UIButtonTypeCustom];
[button1 setFrame:CGRectMake(10.0, 2.0, 88, 40.0)];
[button1 addTarget:self action:#selector(loginPressed) forControlEvents:UIControlEventTouchUpInside];
[button1 setImage:[UIImage imageNamed:#"logoutN.png"] forState:UIControlStateNormal];
UIBarButtonItem *button = [[UIBarButtonItem alloc]initWithCustomView:button1];
self.navigationItem.rightBarButtonItem = button;
self.title=#"Catalog";
popImageView.hidden=YES;
passwordLabel.hidden=YES;
userLabel.hidden=YES;
userNameTextField.hidden=YES;
userPasswordTextField.hidden=YES;
signInButton.hidden=YES;
tableView.hidden=NO;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
searching = NO;
letUserSelectRow = YES;
if(!categoryArray){
categoryArray =[[NSMutableArray alloc] init];
}
if(!userArray){
userArray =[[NSMutableArray alloc] init];
}
if(!subCategoryArray){
subCategoryArray =[[NSMutableArray alloc] init];
}
if(!subCategoryArrayOne){
subCategoryArrayOne =[[NSMutableArray alloc] init];
}
if(!subCategoryArrayTwo){
subCategoryArrayTwo =[[NSMutableArray alloc] init];
}
[self setUpData];
[self setUpDataSub];
[self setUpDataSubOne];
[self setUpDataSubTwo];
int count=[appDelegate.coffeeArray count];
NSLog(#"Arrays Content Are %d",count);
tableView.backgroundView = nil;
[super viewDidLoad];
}
is there any way so that view loads fast
Your view is not loading fast because of I guess those data set operation in viewDidLoad method . I think those are :
[self setUpData];
[self setUpDataSub];
[self setUpDataSubOne];
[self setUpDataSubTwo];
The one thing you could do is to move this operations to perform on the background thread . For that move this operations to the separate function and call that to perform on background from the view did load method :
-(void)dataOperations
{
[self setUpData];
[self setUpDataSub];
[self setUpDataSubOne];
[self setUpDataSubTwo];
}
and in viewDidLoad call this function in background:
[self performSelectorInBackground:#selector(dataOperations) withObject:nil];
Or you can directly call those method from viewDidLoad like :
[self performSelectorInBackground:#selector(setUpData) withObject:nil];