Show AlertView when tapping tab in TabBar - ios

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.

Related

How to add an UIView to the front most view of the whole iOS in the tweak application?

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.

iOS code to dismiss a View with countdown

Im experimenting with iOS 8 Objective-c project to perform a segue to a view controller right when viewDidLoad is presented.
Then this recent new presented view should be dismissed by a 30 seconds countdown to return to the initial view controller.
What would be like the code to dismiss the view with a countdown ? A countdown interface would not be necessary, just the background code.
My initial view controller is called ConfViewController and will perform a segue right on viewDidLoad to BubbleViewController, this should be displayed for 30s then be dismissed to the first one again ConfViewController.
#implementation ConfViewController
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewDidLoad
{
[super viewDidLoad];
The BubbleViewController
#interface BubbleViewController ()
#end
#implementation MessagesViewController {
UIVisualEffectView *blurEffectView;
}
- (void)viewDidLoad
{
self.dataSource = self;
self.delegate = self;
[super viewDidLoad];
Thnx and cheers!
Putting this Code into your bubble view Controllers viewDidLoad or similar and it will dismiss itself after 30 seconds:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(30 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:nil];
});
A quick way to execute any code after some time is to use this snippet:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
//code to be executed after a specified delay
});
Where you should place this code is up to you either in the presenters or in the presented controllers viewDidLoad.
How you should dismiss it depends on the way that you presented it.
Add below line of code in BubbleViewController's viewDidLoad method
//countdown can be according to requirement
[self performSelector:#selector(dissmissView) withObject:nil afterDelay:30];
Now description of dissmissView method and add these method also.
-(void)dissmissView
{
if (self.navigationController.presentingViewController)
{
//presented As ModaL
[self dismissViewControllerAnimated:YES completion:nil];
}
else if(self.navigationController)
{
//Pushed in navigation controller stack
[self.navigationController popViewControllerAnimated:YES];
}
else //added as subView
{
[self.view removeFromSuperview];
}
}

MBprogressHUD not showing as expected

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.

MBProgressHUD blocks user interaction with a tableview

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];
}

wait_fences: failed to receive reply: 10004003?

I am getting this cryptic message: wait_fences: failed to receive reply: 10004003
I have googled and people think it has something to do with not properly dismissing a UITextField or Alert. I have one textfield in my app and I assure you I release it properly using resignFirstResponder, etc...
I get this message when I am opening a MPMusicPickerController from a subview, does that make any difference. I really need to get this fixed because it is messing up my whole app!
Thanks,
Brad
Edit1:
- (IBAction)openMediaPicker:(id)sender {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
MPMediaPickerController *mediaPicker = [[MPMediaPickerController alloc] initWithMediaTypes:MPMediaTypeAny];
mediaPicker.delegate = self;
mediaPicker.allowsPickingMultipleItems = YES;
mediaPicker.prompt = #"Select songs to play";
[self presentModalViewController:mediaPicker animated:YES];
[mediaPicker release];
}
// Media picker delegate methods
- (void)mediaPicker: (MPMediaPickerController *)mediaPicker didPickMediaItems:(MPMediaItemCollection *)mediaItemCollection {
AppAppDelegate *appDelegate = (AppAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.tr2 stop];
[playstopButton setHidden:NO];
[playstopButton setImage:[UIImage imageNamed:#"Stop-Music-Button.png"] forState:UIControlStateNormal];
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
// Assign the selected item(s) to the music player and start playback.
[self.musicPlayer stop];
[self.musicPlayer setQueueWithItemCollection:mediaItemCollection];
[self.musicPlayer play];
}
- (void)mediaPickerDidCancel:(MPMediaPickerController *)mediaPicker {
// User did not select anything
// We need to dismiss the picker
[self dismissModalViewControllerAnimated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationFade];
}
Generally:
You should not do any animations in viewWillAppear only in viewDidAppear. Only prepare your data, outlets etc. in viewWillAppear.
Also a very common case where wait_fences might arise is when you have an animated dialog (Like your MPMediaPickerController) that causes another animated view to appear (Like a custom modal UIViewController) or the like, in which case you need to "postpone" the presentation of the second viewcontroller like this:
[self performSelector:#selector(showMyOtherViewController)
withObject:nil
afterDelay:0.1];
Also check out this answer https://stackoverflow.com/7194182.
Edit
A good way to "debug" conflicting animations is to simply set the animation to NO so in your code instead of
[self presentModalViewController:mediaPicker animated:YES];
[self dismissModalViewControllerAnimated:YES];
Simply do:
[self presentModalViewController:mediaPicker animated:NO];
[self dismissModalViewControllerAnimated:NO];
and check if the wait_fences error goes away and the correct behaviour (but without animation) is achieved. If this is the case you need some of the performSelector:withObject:afterDelay:-magic.
Edit: Please note that you can do the following in iOS 5.0:
[self dismissViewControllerAnimated:YES completion:^{
[self presentViewController:anotherViewController animated:YES completion:NULL]
}
That means that first, the currently presented View Controller (e.g. a ModalViewController) is dismissed and when the animation is finished you can invoke another block. In this case show another UIViewController
I also noticed that replacing clickedButtonAtIndex: with didDismissWithButtonIndex: when using UIActionSheet or UIAlertView seems to make the error message go away.

Resources