I am trying to detect when a ViewController was pushed.
So I followed the doc of Apple http://developer.apple.com/library/ios/#documentation/uikit/reference/UINavigationBarDelegate_Protocol/Reference/Reference.html , about NavegationBar delegate but I didnĀ“t figured out how to make it working successfully.
I placed on my code the following code in my ViewController but it doesn't detect it was pushing.
What I am doing wrong ?
- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item, {
NSLog(#"didPushItem: %#", item);
[self showimage];
}
Not clear what you are needing to do but there are several UIViewController methods for discerning its context. There are two below and a couple more in the docs
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
BOOL pushed = [self isMovingToParentViewController];
printf("viewWillAppear %d\n", pushed);
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
BOOL popped = [self isMovingFromParentViewController];
printf("viewWillDisappear %d\n", popped);
}
You should implement UINavigationControllerDelegate for UIViewController and UINavigationController related tasks.
Here is the link to the documentation:
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UINavigationControllerDelegate_Protocol/Reference/Reference.html
The particular method you want, which would be something like "navigationController:didPushViewController:animated:", does not exist in the protocol.
However, I believe you can achieve the desired behavior using the navigationController:willShowViewController:animated:. Note that this method gets called before the View for the UIViewController is shown and after it has been pushed into the UINavigationController stack.
The -viewWillApear method is reasonable, but it gets called when the view is about to be inserted into the view hierarchy, which may or may not be what you want.
If you want more control of the push/pull progress, you can override
- (void)willMoveToParentViewController:(UIViewController *)parent {
if (nil == parent) {
// Moving to nil parent means being removed from parent
} else {
// Will be inserted as a child view controller of <parent>
}
}
- (void)didMoveToParentViewController:(UIViewController *)parent {
if (nil == parent) {
// Moving to nil parent means was just removed from parent
} else {
// Was just inserted as a child view controller of <parent>
}
}
These will be called just before and after the navigation controller pushes/pops the child view controller.
From the docs...
didMoveToParentViewController:
Called after the view controller is added or removed from a container view controller.
- (void)didMoveToParentViewController:(UIViewController *)parent
Parameters
parent
The parent view controller, or nil if there is no parent.
Discussion
Your view controller can override this method when it wants to react
to being added to a container.
and...
willMoveToParentViewController:
Called just before the view controller is added or removed from a
container view controller.
- (void)willMoveToParentViewController:(UIViewController *)parent
Parameters
parent
The parent view controller, or nil if there is no parent.
Discussion
Your view controller can override this method when it needs to know
that it has been added to a container.
Related
I have view structure like below.
HomeView(Support only portrait mode)
|
|
V
View1(Support all orientation)
|
|
V
View2(Support all orientation)
Problem :
When i am coming back from View2(Landscape mode) to HomeView by calling popToRootViewController method,It did not call supportedInterfaceOrientationsForWindow method of App_Delegate and display
HomeView in landscape mode.
Image:
Note :
Same thing not happens when i came back from View1(Landscape mode) to HomeView by calling popToRootViewController method
it will call supportedInterfaceOrientationsForWindow and all works great.
If I run app using XCode6 in iOS7 all works great.
I read below question but it did not help me.
How to maintain presenting view controller's orientation when dismissing modal view controller?
In above link matt said that iOS8 stop support for friezing orientation, but I did not find it in apple document
if you have any reference link about this change please share.
Question :
1] Why delegate method supportedInterfaceOrientationsForWindow is not calling.
2] Is it possible to have one view with support single orientation and all other will support all orientation.
Thanks
I solve it and post answer as it will may help some one
Problem :
I have below code in supportedInterfaceOrientationsForWindow.
- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
// Suport only portrait mode for home screen
if([self.navigationController.topViewController isKindOfClass:[ViewHome class]])
{
return UIInterfaceOrientationMaskPortrait;
}
return UIInterfaceOrientationMaskAll;
}
But delegate method supportedInterfaceOrientationsForWindow not called
when use popToRootViewControllerAnimated method when there ismore then two view Cotnrollersexists in stack.
Solution :
Step1: Create sub class of Navigation controller.
Step2: Override method popToRootViewControllerAnimated and write code as below
// Overwrite super class method popToRootViewControllerAnimated.
-(NSArray*)popToRootViewControllerAnimated:(BOOL)animated
{
// Only for iOS8 and above
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_7_1)
{
// Array which will contaimn all poped view controllers object.
NSMutableArray *popedControllersArray = [[NSMutableArray alloc] init];
// Tmp created controllers object
NSArray *controllers;
// Hold first view cotnrollers.
UIViewController *firstViewController = [self.viewControllers objectAtIndex:1];
// Pop to first view controllers with no animation.
controllers = [super popToViewController:firstViewController animated:NO];
// Add poped view cotnrollers objects to the array.
[popedControllersArray addObjectsFromArray:controllers];
// Pop to root view controller with animation
[super popViewControllerAnimated:YES];
// Add first view controller object as it is poped by above line.
[popedControllersArray addObject:firstViewController];
// return poped view controllers object.
return popedControllersArray;
}
else
{
// Called super view popToRootViewControllerAnimated method and return popped
// view controllers array.
return [super popToRootViewControllerAnimated:animated];
}
}
Please fill free for any comments and ask for any questions.
I have a view controller in a storyboard that is using a container view. Both have restoration identifiers set. The parent is being saved and restored just fine. The child however is not. Neither -encodeRestorableStateWithCoder: or -decodeRestorableStateWithCoder: are being called on the child view controller.
What's the correct way to save child view controllers that are created with a view container? I can save the child view controller in the parents -encodeRestorableStateWithCoder:, which will cause it to be saved, but I don't have a way of using it during a restore.
Container view controller "does not automatically save references to any contained child view controllers. If you are implementing a custom container view controller, you must encode the child view controller objects yourself if you want them to be preserved".
There are simple rules that i found:
1.Embedded(child) view controller should already be created and added to parent view controller at the state preservation process. So, do not have to do anything if you use storyboard otherwise you'll have to instantiate child view controller and add it manually:
-(void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Did load");
MyChildViewController *childViewController = [MyChildViewController new];
[self addChildViewController:childViewController];
[childViewController didMoveToParentViewController:self];
self.childVC = childViewController;
}
You can add child view at -viewDidLoad or later. Use self.childVC.view.frame = [self frameForChildController]; [self.view addSubview:self.childVC.view]; for this.
2.You no need to save the child view controller in the parent's -encodeRestorableStateWithCoder: himself, but you should encode a reference to that object using -encodeObject:forKey:. If you have reference you can do it like this:
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
NSLog(#"Encode");
UIViewController *childViewController = self.childVC;
[coder encodeObject:childViewController forKey:#"ChildVC"];
[super encodeRestorableStateWithCoder:coder];
}
see https://stackoverflow.com/a/13279703/2492707 to get reference to child VC if you use Storyboard. Or you can write something simple like this:
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder
{
NSLog(#"Encode");
UIViewController *childViewController = [self.childViewControllers objectAtIndex:0]; //[self.childViewControllers lastObject];
[coder encodeObject:childViewController forKey:#"ChildVC"];
[super encodeRestorableStateWithCoder:coder];
}
3.Embedded(child) view controller should already be created and added to parent view controller at the state restoration process. So, if you did everything in the first paragraph, there is nothing more to do here.
4."In this case, however, we do not decode child view controller. We could, but in fact we don't need it.The MyChildViewController object will restore its own state. We only encoded this reference in order to get the runtime to walk the chain down to the MyChildViewController instance and do save-and-restore on it".
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder
{
NSLog(#"Decode");
[super decodeRestorableStateWithCoder:coder];
}
This book helps me for understanding state preservation with container views. Also look for a good example for this book
I think the answer is in the documentation
It is said:
" The UIViewController class saves a reference to the presented view controller and the storyboard (if any) that was used to create the view controller. The view controller also asks the views in its view hierarchy to save out any relevant information. However, this class does not automatically save references to any contained child view controllers. If you are implementing a custom container view controller, you must encode the child view controller objects yourself if you want them to be preserved."
So you could do something like that:
-(void)encodeRestorableStateWithCoder:(NSCoder *)coder {
[super encodeRestorableStateWithCoder:coder];
[self.myChildViewController encodeRestorableStateWithCoder:coder];
}
-(void)decodeRestorableStateWithCoder:(NSCoder *)coder {
[super decodeRestorableStateWithCoder:coder];
[self.myChildViewController decodeRestorableStateWithCoder:coder];
}
And in MyChildViewController do not call super :)
I have view controller as follows
parent view Controller
#interface Parent : UIViewController
{
}
child view Controller
#interface Child : Parent
{
}
Now i want current viewcontroller name in parent viewcontroller, I have searched but got simple clue is.
If it is a navigation based app, you can get the current view controller by,
UIViewController *currentVC = self.navigationController.visibleViewController;
But what is the currect procedure to access the current viewcontroller name in Parent Viewcontroller.
try this
for(UIViewController * view in self.navigationController.viewControllers)
{
if([view isKindOfClass:[Child class]])
{
//child VC is displayed on screen
}
}
Code below can help. I have not tried it but let me know if it worked
Write the following method in Parent class
-(void)getClassName:(NSString*)className{
NSLog(className);
//Your code here
}
Following lines where you need to access the current viewcontroller name
[self getClassName:NSStringFromClass([self class])];
Hope this post was helpful
I have founded the answer,
in Parent ViewController:
- (void)viewDidLoad
{
UIViewController *currentVC = self.navigationController.visibleViewController;
NSLog(#"The Current Class : %#", [self getClassName:currentVC]);
}
- (NSString*) getClassName:(id) obj
{
const char* className = class_getName([obj class]);
NSString *clsName = [#"" stringByAppendingFormat:#"%s",className];
return clsName;
}
When we are calling [super viewDidLoad] from Child ViewController then Parent ViewController was initialized, Here i am taking the class name of the current view controller. So In my Application i dont want to write this line of code in each view controller instead i have written in Parent View Controller.
Note: This work for navigation based app only, because we are getting current visibleViewController from navigationController
Is their any Possibilty to Check which viewController is running in IPhone application Programmatically in Appdelegate
There is no easy answer to this. You need to walk the view controller hierarchy starting with the main window's root view controller. If you encounter a UINavigationController you need to look at the topViewController. Once you get to a UIViewController, you need to look at the modalViewController, if any. If you have any tab bar controllers then you need to look at the currently selected tab.
Things like UISplitViewController complicates things since this can show two view controllers at once.
Here is the start of a category method you could add to UIViewController. This only handles regular view controllers and navigation controllers.
- (UIViewController *)topMostController {
if (self.modalViewController) {
return [self.modalViewController topMostController];
} else {
if ([self isKindOfClass:[UINavigationController class]]) {
UINavigationController *nc = (UINavigationController *)self;
return [nc.topViewController topMostController];
} else {
return self;
}
}
}
Call this from your app delegate on the key window's rootViewController.
Assuming you've set the rootViewController property in your AppDelegate:
[UIApplication sharedApplication].keyWindow.rootViewController;
For view controller it is not possible to get the curent running viewcontroller name.
for that you write one following method in your app delegate file & then call getCurentViewController method in each viewcontroller view did load or view did appear if you are not allocating agin by passing self to it
-(void) getCurentViewController:(UIViewController*) vc
{
if([vc isMemberOfClass:NSClassFromString(#"vcName")])
{
//write your code here
}
else if([vc isMemberOfClass:NSClassFromString(#"vcName1")])
{
//write your code here
}
}
UIViewController *currentViewController = yourRootViewController;
while (currentViewController.presentedViewController) {
currentViewController = currentViewController.presentedViewController;
}
//currentViewController is now your top-most viewController
//I use this same snippet in my production code
Is there a way to be notified when a ViewController is removed from a UINavigationController because the back button was pressed?
You can use viewWillDisappear: in the view controller that is disappearing. If the other view controller needs to be notified, you can use a delegate method to notify it:
//in the disappearing view controller, class MYViewController
-(void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
//do stuff you need to do
if ([self.delegate respondsToSelector:#selector(myViewControllerDidDisappear:)])
[self.delegate myViewControllerDidDisappear:self]; //bottom view controller is delegate
}
In conjunction with eman's method, check
[navController.viewcontrollers count]
If it is one greater than before (you need to maintain a count) then something was pushed. If it is one less, and viewWillDisappear: was called, then the view controller was removed.