I am using MBProgressHUD to show a HUD but it is not showing as expected.
Steps:
User selects a cell in a tableView. Some data is parsed then a warning (UIAlertView) is shown to the user. The user is asked if they want to create a New Game with the selected (cell) user. Cancel/Start Game buttons.
The UIAlertView delegate methods is as follows:
pragma mark - UIAlertView Delegate
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"button %i",buttonIndex);
if (buttonIndex == 0) {
// Cancel button pressed
self.gameNewOpponentuser = nil;
} else {
// Start Game button pressed
[MESGameModel createNewGameWithUser:[PFUser currentUser] against:self.gameNewOpponentuser];
}
}
If the user selects Start Game the GameModel method is run. The game model(NSObject subclass) method is as follows:
pragma mark - Custom method
+(void)createNewGameWithUser:(PFUser *)user1 against:(PFUser *)user2 {
// First we put a HUD up for the user on the window
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
HUD.dimBackground = YES;
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
HUD.removeFromSuperViewOnHide = YES;
// Confirm we have two users to play with.
}
As you can see the HUD is alloc init to the keywindow of the application. However, the HUD is not showing as expected, nothing happens no UI lockup etc. I have put a breakpoint in the above method and can see that it is called however the HUD is not displayed
From the above, I expect the HUD to show up but nothing else happen, i.e. the HUD just remain on screen at the moment...
You are missing the part where you add the HUD to the Window and then showing the HUD. Note that you can add the HUD to the Window or the current view (self.view).
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithWindow:[UIApplication sharedApplication].keyWindow];
[[UIApplication sharedApplication].keyWindow addSubview:HUD]; //<-- You're missing this
HUD.dimBackground = YES;
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
HUD.removeFromSuperViewOnHide = YES;
[HUD showAnimated:YES whileExecutingBlock:^{ //<-- And this
// Do something
}];
Try this:
MBProgressHUD *HUD = [[MBProgressHUD alloc] initWithView:self.view];
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
// Set determinate mode
[HUD setMode:MBProgressHUDModeDeterminate];
[self.view addSubview:HUD];
[HUD show:YES];
You aren't adding it to any view for it to be displayed. So add it to appropriate view.
From the git hub project demo for MBProgressHUD
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
You are not given the code to display the hud. use the following code
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.dimBackground = YES;
HUD.labelText = NSLocalizedString(#"HUDCreateNewGame", #"HUD - Create New Game text");
Ok, I found the issue. I was using clickedButtonAtIndex method for the UIAlertView which was of course holding to the view. I used didDismissWithButtonIndex instead and this works fine now.
Related
My app is a tweak app running in SpringBoard, in which I want to use MBProgressHUD, but it need to specify a view to add to, so how can I get the font most view of the whole iOS?
I should do like that:
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:fronMostView animated:YES];
hud.mode = MBProgressHUDModeText;
hud.labelText = [Localization localize:#"Finished!"];
[hud hide:YES afterDelay:1];
The best place to add this view is AppDelegate. Add view in to appDelegate window will show to top front for whole application. Also it remains on top until you hide or remove this view from appDelegate window.
Create a global object of MBProgressHUD in AppDelegate class and create show/hide methods.
Call this methods respectively for your convenience use.
For Example:
#property (nonatomic, strong) MBProgressHUD *hud;
- (void) showProgress:(NSString *)message {
// Create a loading view
if (!self.hud) {
_hud = [MBProgressHUD showHUDAddedTo:fronMostView animated:YES];
self.hud.mode = MBProgressHUDModeText;
// Add Progress to window.
[self.window addSubview:self.hud];
}
self.hud.hidden = NO;
self.hud.labelText = [Localization localize:message];
}
- (void) hideLoadingMessage {
self.hud.labelText = [Localization localize:#"Finished!"];
[self.hud hide:YES afterDelay:1];
}
try
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
or
UIWindow *window = [UIApplication sharedApplication].windows.lastObject;
Then
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:window animated:YES];
Here is a topic about this, maybe it'll be useful.
What I need
I'd like to show an UIAlertView "Loading..." when I tap on a tab in my tabBar.
Reason why I want to do that
This is because that particular tab contains a UIWebView and is very slow, so when I tap on that tab it seems like my app is doing absolutely nothing for a few seconds. It is very ugly, so I'd like to show something to make the user know that the app is actually working.
Questions
In which position do I have to put it? If I write it in the ViewDidLoad, the AlertView is shown after those orrible few seconds. Is AlertView the best choice?
Thank you all.
add MBProgressHUD to your UIWebView viewDidLoad method
- (void)viewDidLoad {
[super viewDidLoad];
self.webView.delegate = self;
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Loading...";
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[hud hide:YES];
}
UIAlerView is not a good idea.
//Delegate method of UIWebView
- (void)webViewDidStartLoad:(UIWebView *)webView
{
if(![[UIApplication sharedApplication] isNetworkActivityIndicatorVisible])
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
}
}
//Delegate method of UIWebView
- (void)webViewDidFinishLoad:(UIWebView *)webView_
{
if([[UIApplication sharedApplication] isNetworkActivityIndicatorVisible])
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
}
}
Set your tabBar as a delegate on viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
//Setting tabBarController as a delegate
self.tabBarController.delegate = self;
}
On your interface at .h method add delegate <UITabBarControllerDelegate>
Implement this function and add your loading view, for each time that you press tabBar. The method below gets executed always when the user taps an item on tabbar.
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
//Show loading form here
[MBProgressHUD showHUDAddedTo:self.view animated:YES];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
dispatch_async(dispatch_get_main_queue(), ^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
});
});
}
P.S You need to add this method and set to delegate to every viewController which you need to show the alert view (Loading View)
For a loading view you can also load use MBProgressHUD as KingBabar pointed out. It has great features.
I'm doing an App with a MKMapView that has a back button the UIView which contain the MKMapView in order to go to main menu, that's ok, but when I want to load again the UIView with the MKMapView my App crash, it doesn't gives any error, just crash and show machine code where it crashed, but it says first: com.apple.CoreLocation.ConnectionClient.0x1e5d5220 and then lot of machine code.
The crash report is here:
I have to add, that the first time I load that UIView it's 100% working.
Thanks for your help.
PS: Why I say dealloc? because I think doing something like dealloc probabbly will fix my problem and will be the same as running the first time.
EDIT1:
My - (void) viewDidLoad; method.
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *response = [self sendPostToURL: #"http://hidden.php"
withPost: #"hidden"];
[self tratarXML: response];
yo = #"Posición actual";
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.distanceFilter = kCLDistanceFilterNone;
[self.mapView setDelegate: self];
[self.mapView setZoomEnabled: NO];
[self.mapView setScrollEnabled: NO];
if ([CLLocationManager locationServicesEnabled])
{
self.locationManager.delegate = self;
self.mapView.showsUserLocation = YES;
[self.mapView setMapType: MKMapTypeStandard];
[self.mapView setUserTrackingMode: MKUserTrackingModeFollowWithHeading animated: NO];
[self.locationManager startUpdatingLocation];
//[self.locationManager startUpdatingHeading];
self.mapView.userLocation.title = yo;
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:#"Debe activar la localización en esta aplicación para funcionar"
delegate:self
cancelButtonTitle:#"Aceptar"
otherButtonTitles:nil, nil];
[alert show];
}
}
EDIT2:
My back button code:
- (IBAction) iniciar: (id)sender
{
if ([iniciar.title isEqualToString:#"Volver"])
{
menuViewController *obj = [[menuViewController alloc] initWithNibName:#"menuViewController" bundle:nil withUser:user];
[self presentViewController:obj animated:YES completion:nil];
}
else
{
// censored
}
I'm using simple *.xib navigator, not storyboard, etc...
EDIT3:
The menu button that load the MKMapView UIView
- (IBAction) TEST: (id)sender
{
mapaViewController *obj = [[mapaViewController alloc] initWithNibName: #"mapaViewController" bundle: nil withUser: user];
[self presentViewController:obj animated:YES completion:nil];
}
There are 3 things that are wrong:
Your back button code should not call a presentViewController but a dismissViewController. Right now you are adding view controller after view controller! When you go back you want to instead get rid of your view controller.
In the back button code, add self.locationManager.delegate = nil;
Similarly, in the back button code, add self.mapView.delegate = nil;
That should do it.
It looks like you're doing a series of presentViewController calls to go from main menu to the map view controller, and then back to the main menu. This is not how it should be done. You probably shouldn't be doing modal transitions at all, but if you do, you should have the main menu dismiss the map view controller, not have the map view controller present another main menu controller.
The better way to do this would be with a navigation controller. Main menu should be the root view controller of a navigation controller, and you would push to go to the map view controller. You will automatically get a back button in the navigation bar, which will take you back (to the same instance) of the main menu controller. No need for any back button code. All this would be much easier to implement in a storyboard.
I have a uitableview which loads data from internet and during this period im displaying MBProgressHUD. But the problem is the user cannot touch anything including previous page button before the table loads. Here is my codein two different classes:
//PROBLEM METHOD 1
- (void)viewDidLoad
{
[super viewDidLoad];
[tableEtkinlikler reloadData];
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Açılıyor...";
HUD.userInteractionEnabled = NO;
[self performSelector:#selector(loadEtkinliklerTitlesAndImages) withObject:nil afterDelay:0];
tableEtkinlikler.dataSource = self;
tableEtkinlikler.delegate = self;
}
I have the same problem with a button also..In it im loading data from internet..
//PROBLEM METHOD 2
- (IBAction)AktivitelerButtonClicked:(UIButton *)sender
{
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Açılıyor...";
HUD.userInteractionEnabled = NO;
[self performSelector:#selector(openAktivitelerWindow) withObject:nil afterDelay:0];
}
I believe for me that is the point of MBProgressHUD , it gives you the opportunity show a HUD while your tasks are completed, once your tasks are completed you dismiss it so user can interact with completed data.
However In some cases loading data takes so long so you might want to let the user decide to continue , choose another option or just simply go back
in your code this HUD.userInteractionEnabled = NO; should work but problem might be that showHUDAddedTo:self.view you do not use the highest view possible in the view hierarchy.
Try to use this:
- (IBAction)showSimple:(id)sender {
// The hud will dispable all input on the view (use the higest view possible in the view hierarchy)
HUD = [[MBProgressHUD alloc] initWithView:self.navigationController.view];
[self.navigationController.view addSubview:HUD];
HUD.userInteractionEnabled = NO;
// Regiser for HUD callbacks so we can remove it from the window at the right time
HUD.delegate = self;
// Show the HUD while the provided method executes in a new thread
[HUD showWhileExecuting:#selector(loadEtkinliklerTitlesAndImages) onTarget:self withObject:nil animated:YES];
}
I'm trying to show a mix of HUDs in my app, so for example, when a user taps "login", I want my HUD to display the spinner saying "logging in...", then change to a checkmark image saying "logged in!", then hide. I'm trying to accomplish this using the following code:
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
HUD.labelText = #"Logging in";
\\Do network stuff here, synchronously (because logging in should be synchronous)
\\ Then upon success do:
HUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"checkmark.png"]];
HUD.mode = MBProgressHUDModeCustomView;
HUD.labelText = #"Logged in!";
sleep(2);
[MBProgressHUD hideHUDForView:self.view animated:YES];
Problem here, is that the sleep(2) is being applied to the initial spinner, and not the checkmark HUD. So the spinner is showing for a longer period of time, and the checkmark disappears after a split second. How can I do it so that the checkmark stays there for a longer time before the HUD hides?
Thanks!
As best practice, don't use sleep. Try using the "performSelector:withObject:afterDelay" method. Create a method that does the
[MBProgressHUD hideHUDForView:self.view animated:YES];
action and call it after a predefined delay of your choice. Don't forget that you're handling UI so make sure you're calling this on the main thread.
I would create two HUDs. The first one for the "waiting" part, and the second one for the success. Start the loadingHUD before your network task, and hide it when you are done :
MBProgressHUD *loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.mode = MBProgressHUDModeIndeterminate;
loadingHUD.labelText = #"Please wait...";
loadingHUD.detailsLabelText = #"Connection in progress";
[loadingHUD show:YES];
// Do the network stuff here
[loadingHUD hide:YES];
Right after that, to notify the success, create the successHUD as you want it, and hide it after delay :
MBProgressHUD *successHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
successHUD.mode = MBProgressHUDModeCustomView;
successHUD.customView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"checkmark.png"]];
successHUD.labelText = #"Logged in !";
[successHUD show:YES];
[successHUD hide:YES afterDelay:2.0];
Your success HUD will show up for 2 seconds, and hide automatically.
That's how I always use MBProgressHUD.