A second viewcontroller has mailcontroller and after finishing mail, it post a message to the mainviewcontroller to remove the secondviewcontroller's view. but it's not happening. The mailcontroller appearing and disappearing seem to interferes with finish function of the mainviewcontroller.
secondviewcontroller:
[self dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:#"finish" object:nil];
mainviewcontroller:
-(void) finish:(NSNotification *)notif {
[MyviewController.view removeFromSuperview];
}
The removal of the second view controller should be delayed until your modal controller is really removed. What I have done is following:
[self dismissModalViewControllerAnimated:YES];
m_shouldHide = YES;
And then:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ( m_shouldHide )
{
[self dismissModalViewControllerAnimated:YES];
m_shouldHide = NO;
}
}
Related
I have a modalViewController that comes up over the top of a viewController with a tableView. When the user clicks a button on the modalViewController I want to reload the tableView within the viewController with this:
[tableView1 reloadData];
I do not want to put the reload in the viewDidAppear or viewWillAppear methods as they get called when i do not need the tableView to reload (i.e. when the user clicks the back button to return to the tableView).
Is there a way to do this?
Try
1) write one method which reloads the table data.
2) Call it on the back button clicked.
This is the classic delegate pattern problem, in your modal view controller you need a delegate reference to the current view controller presenting it
//Modal
#protocol ModalVCDelegate
- (void)tappedBackButton;
#end
#class ModalVC: UIViewController
#property id<ModalVCDelegate> delegate;
#end
#implementation
- (void)backButtonTapped:(id)sender
{
if (self.delegate)
[self.delegate tappedBackButton];
}
#end
Now, in your presenting VC, just process this delegate message
//Parent VC
- (void)showModal
{
ModalVC *vc = [ModalVC new];
vc.delegate = self;
//push
}
- (void)tappedBackButton
{
[self.tableView reloadData];
//close modal
}
You can use delegate . If find it more harder then alternative is to use NSNotificationCenter. You can see accepted answer for Refreshing TableView. This is really very short, easy and understandable way.
using Notification like bellow Method:-
Create NSNotificationCenter at yourViewController's ViewdidLoad Mehod
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ReloadDataFunction:)
name:#"refresh"
object:nil];
[super viewDidLoad];
}
-(void)ReloadDataFunction:(NSNotification *)notification {
[yourTableView reloadData];
}
Now you can Call this Notification from your modelViewController BackButton or else you want from calling this Refresh notification like putting this line of code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:self];
NOTE: postNotificationName:#"refresh" this is a key of particular Notification
Try to use this one
Make a Button and click on this button and than you can reload your data.
This button make custom and use it on background.
- (IBAction)reloadData:(id)sender
{
[tblView reloadData];
}
You can use NSNotification to refresh table on ViewController.
Inside viewController :
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Write code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadMainTable:)
name:#"ReloadTable"
object:nil];
- (void) reloadMainTable:(NSNotification *) notification
{
[tableView reload];
}
Inside ModelViewController:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:nil];
Here you can also send custom object instead of nil parameter. But be care full about removal of NSNotification observer.
i have an action that allows me to present a ModalViewController and show the UITextField as a first responder, the problem is when this ModalViewController will come up it takes a little time, the cause is the keyboard, and when i grab the code to the viewDidAppear the keyboard take a little time to show up, so how can i do to make the UIViewController comes up quickly?
- (IBAction)goToModalViewController
{
ModalSearchViewController *msvc = [[ModalSearchViewController alloc] init];
self.msvc.context = context;
self.msvc.delegate = self;
[self.msvc setModalTransitionStyle:UIModalTransitionStyleCrossDissolve ];
[self presentModalViewController:msvc animated:YES];
}
The viewWillAppear of the ModalViewController:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:YES];
[findTextField becomeFirstResponder];
}
Try like this in the viewWillAppear.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//[findTextField becomeFirstResponder];
[findTextField performSelector:#selector(becomeFirstResponder) withObject:nil afterDelay:0.3];
}
I'm trying to present a Modal View Controller when the app enters in foreground.. These are my files:
AppDelegate.m :
#import "AppDelegate.h"
#import "MainViewController.h"
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[self.window makeKeyAndVisible];
MainViewController * vc = [[MainViewController alloc]init];
[vc myMethodHere];
}
MainViewController.h :
//[..]
-(void) myMethodHere;
MainViewController.m :
-(void)myMethodHere{
NSLog(#"myMethodHere Activated.");
TWTweetComposeViewController *tweetViewController = [[TWTweetComposeViewController alloc] init];
[self presentModalViewController:tweetViewController animated:YES];
}
NSLog(#"myMethodHere Activated.") works.. so I can't understand why "presentModalViewController" doesn't! What should I edit/add? Maybe a delay? Thanks for your help..
p.s. I know my english sucks.. Forgive me :)
I wouldn't rely on the methods in your app delegate for this (even though it seems like the obvious solution) because it creates unnecessary coupling between your application delegate and the view controller. Instead, you can have MainViewController listen for the UIApplicationDidBecomeActive notification, and present the tweet composer view controller in response to this notification.
First, register for the notification in -viewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(myMethodHere) name:UIApplicationDidBecomeActiveNotification object:nil];
}
Now, when this notification is received when your app returns from the background, myMethodHere will be invoked.
Lastly, remember to remove yourself as an observer when the view unloads.
- (void)viewDidUnload
{
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil];
}
So I have a UITabBarController app and I want to display a login page, and so I did:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(userDidLogin:) name:UserDidLoginNotification object:nil];
LoginViewController* loginViewController = [[LoginViewController alloc] init];
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:0];
[self.tabBarController.selectedViewController presentModalViewController:loginViewController animated:NO];
[loginViewController release];
Inside my LoginViewController I can as well show another modalViewController:
- (void) twitterLogin: (UIViewController *) askingView
{
UIViewController *controller = [SA_OAuthTwitterController controllerToEnterCredentialsWithTwitterEngine: _twitter delegate: self];
if (controller) {
self.askingView = askingView;
[askingView presentModalViewController: controller animated: YES];
}
}
I have the following method where the askingView is the LoginViewController,
when I want to dismiss this I do:
[self.askingView dismissModalViewControllerAnimated:YES];
[[NSNotificationCenter defaultCenter] postNotificationName:UserDidLoginNotification object:nil];
However, this doesn't dismiss the LoginViewController and show the UITabBarController views.. it just dismisses my modalViewController shown from the LoginvVIewController. What am I doing wrong here? I am also getting the following error:
attempt to dismiss modal view controller whose view does not currently appear. self = <LoginViewController: 0x2aff70> modalViewController = <SA_OAuthTwitterController: 0x2d2a80>
2011-09-16 09:45:37.750 VoteBooth[4614:707] attempt to dismiss modal view controller whose view does not currently appear. self = <MainViewController: 0x29fec0> modalViewController = <LoginViewController: 0x2aff70>
In order to dismiss a modal view that is presented over another modal view, you have to call dismissModalViewControllerAnimated: on the parent of the parent. I have used this in some of my apps and it has worked beautifully for me (after many painstaking hours trying to figure it out). Here is exactly what I've used:
[[[self parentViewController] parentViewController] dismissModalViewControllerAnimated:YES];
if ([self respondsToSelector:#selector(presentingViewController)]) {
[self.presentingViewController.presentingViewController dismissModalViewControllerAnimated:YES]; // for IOS 5+
} else {
[self.parentViewController.parentViewController dismissModalViewControllerAnimated:YES]; // for pre IOS 5
}
If you have a dynamic UX and do not know how many parents to go to, you can use this recursive function to figure it out...
- (void) goHome
{
//Dismiss modal back to home page
int numberOfVcsToDismiss = [self findRootViewController:self];
[self dismissToRootVc:numberOfVcsToDismiss];
}
- (int) findRootViewController:(UIViewController*)vc
{
if(vc)
{
return 1 + [self findRootViewController:vc.presentingViewController];
}
return 0;
}
- (void) dismissToRootVc:(int)count
{
if(count == 1)
[self dismissViewControllerAnimated:YES completion:^{}];
if(count == 2)
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 3)
[self.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 4)
[self.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
if(count == 5)
[self.presentingViewController.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:^{}];
//etc....
}
I have a tableview controller under a navigation controller. Some of my table cells contain text fields, so when I tap on them, a keyboard will show up and automatically resize (shrink) the bounds of my tableview. The bounds is then restored when the keyboard is dismissed programmatically by calling resignFirstResponder on my text field.
Some of my cells would push a new view controller into the view stack when tapped on, so I first resign my current textfield before pushing the view controller:
- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (currentEditingTextField != nil) {
[currentEditingTextField resignFirstResponder];
currentEditingTextField = nil;
}
return indexPath;
}
The problem is when I navigate back to my table view, the bounds of the tableview is sized as if the keyboard is still there. I know this because the scroll indicator only reaches right above where the keyboard was and there is empty view space below the table view.
Anybody experienced this and know of a solution? Thanks
I had the same issue. I found that I need to prevent call [UIView viewWillDisappear:] before the keyboard hides.
My solutions for this.
// useful method, thus I don't need to remember current first responder
#interface UIView (FindAndResignFirstResponder)
- (BOOL)findAndResignFirstResonder;
#end
// ---
#implementation UIView (FindAndResignFirstResponder)
// http://stackoverflow.com/questions/1823317/how-do-i-legally-get-the-current-first-responder-on-the-screen-on-an-iphone
- (BOOL)findAndResignFirstResonder {
if (self.isFirstResponder) {
return [self resignFirstResponder];
}
for (UIView *subView in self.subviews) {
if ([subView findAndResignFirstResonder]) {
return YES;
}
}
return NO;
}
#end
// ---
#interface MyTableViewController : UITableViewController {
// some booleans required to track state of keyboard and view
BOOL hidingKeyboard;
BOOL viewWillDisappear;
BOOL viewWillDisappearAnimated;
}
// methods for keyboard event handling
- (void)keyboardWillHide:(id)sender;
- (void)keyboardDidHide:(id)sender;
#end
// ---
#implementation MyTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
// adding observer for keyboard events (notifications)
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
hidingKeyboard = NO;
viewWillDisappear = NO;
}
- (void)viewDidUnload {
[super viewDidUnload];
// removing observer
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)viewWillDisappear:(BOOL)animated {
// finding and resigning first responder
[self.view findAndResignFirstResonder];
if (hidingKeyboard) {
// if keyboard hide animation in process,
// remembering to run [super viewWillDisappear:] after keyboard hides
viewWillDisappear = YES;
viewWillDisappearAnimated = animated;
} else {
// if there is no keyboard hide animation,
// calling super immediately
[super viewWillDisappear:animated];
}
}
- (void)keyboardWillHide:(id)sender {
hidingKeyboard = YES;
}
- (void)keyboardDidHide:(id)sender {
hidingKeyboard = NO;
if (viewWillDisappear) {
// calling [super viewWillAppear:] after keyboard hides, if required
viewWillDisappear = NO;
[super viewWillAppear:viewWillDisappearAnimated];
}
}
#end