Speed up keyboard dismissing or wait until it's done - iphone

I'm having an issue with my save button in a modal UINavController. When I press the save button, I'm dismissing the keyboard if it is still up, validating the data from the text fields, then showing a UIProgressView while I send my info out.
My problem is that the keyboard isn't getting out of the way fast enough, so keyboard is still up when it is time to show the UIProgressView and it is getting added towards the bottom of my view and it looks stupid.
I can hit the return key, and the keyboard drops, then press save, no issues. But if the user skips the keyboard return key and goes right for the top right save button, I have issues.
Ideally I'd like to implement a short wait statement for it to drop out of sight. Or perform my validation after a delay, but nothing I have tried is working. Please help.
Code Example:
// end edit mode - should kill all keyboards
[[self.tableView superview] endEditing:YES];
// make sure everything is entered correctly and validates
[self validateEntryFields]; // keyboard not gone when this finishes
if (valid) { // progress view shows up towards bottom of view
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Adding User";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(sendNewUserInformation) onTarget:self withObject:nil animated:YES];
}

You may use keyboard notification (it would be more correct solution than based on timer):
[notificationCenter addObserver: self selector: #selector(keyboardDidHide:) name: UIKeyboardDidHideNotification object: nil];
And show your progress view in keyboardDidHide: method.

If a small delay would be working you could try the following code between your validation and your if statement where you decide whether or not you will showing the progress view.
You can use the NSTimer object:
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(mumboJumbo:)userInfo:nil repeats:NO];
And add your code into a method like:
-(void)mumboJumbo:(id)sender{
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Adding User";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(sendNewUserInformation) onTarget:self withObject:nil animated:YES];
}
If I understood correctly your problem that should work.

Related

Checking MBProgressHUD status if it hide/show

I'm displaying some views,webVies and while they are loading i display an ProgressHud with waiting message. I'm using an instance of that object :
MBProgressHUD * progrssHUD
Using the show and hide methods to control over loading windows. In some views i would like to add view only after the hide method is turned on - meaning no window displayed now.
How can i check from any interface what is that status of MBProgressHUD and only after status X to do something?
If you see the implementation of MBProgresshud then you will find that when they are hiding it they are setting it's alpha 0 and when they are showing it they are setting it alpha 1.
So you can use this property to check whether it is hidden or shown.
i.e
if(progrssHUD.alpha == 0){
//perform hide operation
}else{
//Perform show operation
}
-(IBAction)SHOW{
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.delegate = self;
[HUD show:YES];
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(showHUD) onTarget:self withObject:nil animated:YES];
}
- (void)hudWasHidden:(MBProgressHUD *)hud {
// Remove HUD from screen when the HUD was hidded
[HUD removeFromSuperview];
[HUD release];
HUD = nil;
}
THE METHOD showWhileExecuting CALLING THE HUD WAS ACTIVE WHILE THE DELEGATE METHOD WILL COME.

MBProgressHUD display messages one over the other

In the viewDidload method, i am using MBProgressHUD to show an activity indicator until data is downloaded from the net, and thereafter to check if the application has enabled GPS. based on this i alert the user using MBProgressHUD.
My code;
ViewDidLoad
hudForDownloadData = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view hudForDownloadData ];
hudForDownloadData .delegate = self;
hudForDownloadData .labelText = #"Loading";
hudForDownloadData .detailsLabelText = #"updating data";
[hudForDownloadData showWhileExecuting:#selector(downloadDataFromWebService) onTarget:self withObject:nil animated:YES];
[self downloadDataFromWebService]; // This method is called, and then data is downloaded from the webservice, once the data is downloaded i will remove the `MBProgressHUD ` alert
Now i am checking if the application has enabled access to GPS, and alert the user if not.
hudForGPS = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
hudForGPS .delegate = self;
hudForGPS .labelText = #"Loading";
hudForGPS .detailsLabelText = #"updating data";
[hudForGPS showWhileExecuting:#selector(checkIfApplicationEnabledGPS)
onTarget:self withObject:nil animated:YES]; // This will only take a
maximum of 2-3 seconds. and i will remove it after that
The problem is that; when the internet/wifi is down, the hudForDownloadData will continuously animate (display uiactivityindicator). In the meantime hudForGPS will also execute. But it will display below hudForDownloadData . So the user will not be able to see it.
What i want to do is to execute the checkIfApplicationEnabledGPS first, and wait till its alert finishes (it will only take 2-3 seconds), and then load execute the downloadDataFromWebService where if the internet/wifi is not available it will display forever.
How can i do this programatically ?
Execute checkIfApplicationEnabledGPS first and when it is finished,you show an alert box,If you are using UiAlertView to show the alert then you can handle it's delegate:-
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
when the user presses ok button in UiAlert view you can override the above delegate with hudForDownloadData
In this way both the checkIfApplicationEnabledGPS and hudForDownloadData will be executed one after the other

Activity Indicator not starting animation straight away

I initialize an activity indicator and in a button press action I start it animating and call the next view to display.
-(IBAction) downloadButtonPressed:(id)sender {
NSLog(#"Download Button Pressed");
indicator.hidden = NO;
[indicator startAnimating];
if (addviewcontroller == nil)
addviewcontroller = [[AddViewController alloc]init];
[self.view addSubview:addviewcontroller.view];
[addviewcontroller setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:addviewcontroller animated:YES];
}
When I press the button, the activity indicator doesn't start immediately. It starts when the other view is called. The indicator is displayed for a second, but when the button is pressed it takes some time to load the other view.
I dont know why the indicator shows for a second without starting.
Try this :
-(IBAction) downloadButtonPressed:(id)sender
{
NSLog(#"Download Button Pressed");
indicator.hidden = NO;
[indicator startAnimating];
[self performSelector:#selector(showController) withObject:nil afterDelay:0.1f];
}
- (void)showController {
if (addviewcontroller == nil)
addviewcontroller = [[AddViewController alloc]init];
[self.view addSubview:addviewcontroller.view];
[addviewcontroller setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
[self presentModalViewController:addviewcontroller animated:YES];
}
That should do the trick ;-)
EDIT
I just noticed that there is a problem in your code, you are adding your addviewcontroller twice. One by adding it as a subview of the actual view controller, and one by modally presenting another view controller. You should remove one of the statements from this function.

Refresh tableView when app becomes active

I know there have been a couple questions asked similar to this, but I think my issues is a little different, so bear with me.
I have a tabbed view app with table views set in 2 of the 3 tabs. I want to be able to refresh just the table view of the selected tab when the app wakes back up. I have tried using the notification center to tell my tab to refresh, but it makes the other tab crash because it is stealing the view from my progress hud. I will put some code here, so hopefully I can find a solution that will work for me.
Tab 1 ViewController
- (void)viewDidLoad {
// becomeActive just calls viewDidAppear:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[super viewDidLoad];
}
-(void)viewDidAppear:(BOOL)animated {
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Updating";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(refreshData) onTarget:self withObject:nil animated:YES];
}
Tab 2 ViewController
- (void)viewDidLoad
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.navigationItem.title = [defaults valueForKey:#"companyName"];
self.view.backgroundColor = background;
tableView.backgroundColor = [UIColor clearColor];
tableView.opaque = YES;
tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
// becomeActive just calls viewDidAppear
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(becomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
if (_refreshHeaderView == nil) {
EGORefreshTableHeaderView *view = [[EGORefreshTableHeaderView alloc] initWithFrame:CGRectMake(0.0f, 0.0f - self.tableView.bounds.size.height, self.view.frame.size.width, self.tableView.bounds.size.height)];
view.delegate = self;
[self.tableView addSubview:view];
_refreshHeaderView = view;
[view release];
}
// update the last update date
[_refreshHeaderView refreshLastUpdatedDate];
}
-(void)viewDidAppear:(BOOL)animated {
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = self;
HUD.labelText = #"Updating";
HUD.detailsLabelText = #"Please Wait";
[HUD showWhileExecuting:#selector(updateBoard) onTarget:self withObject:nil animated:YES];
// update the last update date
[_refreshHeaderView refreshLastUpdatedDate];
}
With this setup, my application will refresh tab 2 just fine, assuming that tab 2 was the last tab open before you closed the application. If I switch to tab 1 when I close, upon restarting the app, the notification calls tab 2 first and steals the view out from under my progress hud, so when I try to call the viewDidAppear method, the view is null and the app crashes. I either need to figure out how to implement the notification center better so it doesn't crash the other tab, or a better way overall to just refresh when the app becomes active. Looking forward to a good answer. Thanks in advance.
EDIT
When I run with this setup, it aborts inside the MBProgressHUD
- (id)initWithView:(UIView *)view {
// Let's check if the view is nil (this is a common error when using the windw initializer above)
if (!view) {
[NSException raise:#"MBProgressHUDViewIsNillException"
format:#"The view used in the MBProgressHUD initializer is nil."]; // <-- Aborts on this line, so they know it can happen
}
id me = [self initWithFrame:view.bounds];
// We need to take care of rotation ourselfs if we're adding the HUD to a window
if ([view isKindOfClass:[UIWindow class]]) {
[self setTransformForCurrentOrientation:NO];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(deviceOrientationDidChange:)
name:UIDeviceOrientationDidChangeNotification object:nil];
return me;
}
Main problem here that notifications are received by all views, whether they will appear or not. Good practice would be to notify only those views which will appear in screen
you can use application delegate's (void)applicationWillEnterForeground:(UIApplication *)application method to handle change in application instead of notification.
if problem is all about refreshing tab that is on screen then keeping track of change in tab in AppDelegate and using that when application enters foreground would be better idea over notification.
Other option is to use viewWillAppear method in tabbarcontroller. When this method gets called, you can refresh current tab.
There really isn't much out there to help answer this question. #Learner gave me an idea that ultimately led to how I resolved this issue.
Since all of the logic I have works, the issue was to prevent the HUD from stealing the view from the other one since they both get called when they respond to the notification event. So in my -becomeActive event for both tabs, I added a check if the selectedIndex was a match for the current tab, if not, no refresh. Worked like a charm.
-(void)becomeActive:(NSNotification *)notification {
// only respond if the selected tab is our current tab
if (self.tabBarController.selectedIndex == 1) { // just set the number to your tab index
[self viewDidAppear:YES];
}
}

UIImagePickerController not loading in viewDidLoad for iPhone SDK

I'm trying to show a UIImagePickerController as soon as one of my view controller loads. I'd like to this without the user having to press a button so I overrode the viewDidLoad method as follows:
- (void)viewDidLoad {
[super viewDidLoad];
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.allowsImageEditing = YES;
imagePickerController.delegate = self;
[self presentModalViewController:imagePickerController animated:YES];
[imagePickerController release];
}
This compiles and runs, however when the view controller is loaded the image picker is not displayed. This code works fine if I attach it to an event of a button for example. Any ideas?
Thanks.
I had the same problem but solved it. Try using
-(void) awakeFromNib {
}
It will load just after everything else loads.
Try putting the code in
-(void)viewDidAppear
That even runs every time the view appears on the screen though (including when it appears after you dismiss the UIImagePicker), so you might have to add a BOOL value to make it only happen the first time it shows, or when you want it (i.e. not after dismissing a modal view).
It seems that viewDidLoad is too early to use presentModalViewController:animated:. I'd sugget to fork off a one-shot timer to call the method from next run loop iteration:
[NSTimer
scheduledTimerWithTimeInterval:0
target:self
selector:#selector(onLoadTimer:)
userInfo:nil
repeats:NO];
add the following method:
- (void)onLoadTimer:(id)unused
{
[self presentModalViewController:imagePickerController animated:YES];
[imagePickerController release];
}