How do I check if an UIViewController is currently being displayed?
My UIViewControllers are listening for NSNotifications - even if when they are not displayed (ie not shown). So I could have 10 UIViewController in the background observing NSNotifications from NSNotificationCenter. When an NSNotification is posted and received by the UIViewController, I'd like to find out if it is currently being shown. If it is not, I will just set a boolean so that it will processed when the View is presented. If it currently being display, I will do more things like update tables immediately, and so forth...
You need to check if your viewcontroller is on top of the stack of navigationcontroller's viewcontroller array. A sample code is,
if (self.navigationController.topViewController == self) {
//the view is currently displayed
}
You can use this inside the viewWillAppear method to check whether the current view is visible.
Check to see if it's attached to the window. If it's not nil it's in hierarchy which is attached to the screen (of course it could be off the bounds of the screen, covered by some other view or have the hidden flag set)
if (myViewController.view.window) {
// I'm attached to the window
} else {
// not attached to the window
}
You can use flags in viewWillAppear and viewWillDisappear methods for this.
Why don't you remove the notification listener in viewWillDisappear and add it in viewWillAppear?
Edit: misread his question, sorry.
Suggested answer: set your own flag (BOOL) in viewDidDisappear and viewDidAppear.
Specify title to each ViewController and then get the title of current ViewController by the code given bellow.
NSString *currentController = self.navigationController.visibleViewController.title;
Then check it by your title like this
if([currentController isEqualToString:#"myViewControllerTitle"]){
//write your code according to View controller.
}
I think that checking of viewController.view.superview should works.
It's too late to replay on this question.
To check the instance of a UIViewController is currently on the top of the screen or to check if it is showing on screen, you can put a check like:
// Get the topmost view showing on the screen as below
UIViewController * currentVC = ((UINavigationController*)app.window.rootViewController).visibleViewController;
// Now check whether the viewcontroller you want to show is the same as the currently showing view controller.
if (currentVC.class == myVC.class) { // Here myVC is any/new instance of the viewcontroller you would like to check or show (if not shown).
// If both are same then it returns true and executes this block of code.
}
One more alternative which is based on checking window property
if viewController.viewIfLoaded?.window != nil {
// visible
}
Related
I am using Pyobjc to create a NSStatusItem. When it is clicked, I am showing an NSPopOver. This is working fine. However, my requirement is to show the popover as soon as the application starts without any action by the user. Calling the callback directly in finishLaunching is not working. Is there any way to achieve this? It will be good enough even if can just simulate the click on NSStatusView.
class TestApp(NSApplication):
def finishLaunching(self):
# Make statusbar item
statusbar = NSStatusBar.systemStatusBar()
self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)
self.statusitem.setTarget_(self)
self.statusitem.setAction_('statusItemClicked:')
self.icon = NSImage.alloc().initByReferencingFile_('app-icon.png')
self.icon.setScalesWhenResized_(True)
self.icon.setSize_((20, 20))
self.statusitem.setImage_(self.icon)
self.statusitem.setHighlightMode_(1)
# self.statusItemClicked_(None)
def statusItemClicked_(self, notification):
self.viewController = SimpleXibDemoController.alloc().initWithWindowNibName_("Login")
# Show the window
self.viewController.showWindow_(self.viewController)
rect = self.statusitem.valueForKey_('button').frame()
self.viewController.popover.showRelativeToRect_ofView_preferredEdge_(rect, self.statusitem.valueForKey_('button'), NSMaxYEdge)
I finally got a somewhat sketchy solution. I have a method which positions the popover like so:
- (IBAction)showPopover:(id)sender {
[popover showRelativeToRect:self.statusItemView.bounds ofView:self.statusItemView preferredEdge:NSMinYEdge];
}
In applicationDidFinishLaunching, or finishLaunching in your case, instead of calling the method directly I called it with performSelector instead:
[self performSelector:#selector(showPopover:) withObject:self afterDelay:0];
Even setting the delay to 0 works, which I do not know why, and it now positions the popover correctly.
Edit: This seems to only work situationally. Even by creating a view controller and calling it from viewDidAppear, the popover only gets positioned half of the time.
Edit 2: I added a window controller to the status item's window, and overrode windowDidLoad. However as it turned out, the window is loaded before I can even set the controller's window so windowDidLoad is not called.
You have to wait until the view appears to present the NSPopover. Override viewDidAppear in your NSViewController subclass and present it there. (Or override loadView if your minimum deployment target is less than OS X Yosemite.)
I have a UITabBarController that has 3 UINavigationControllers in my AppDelegate and I want to know how to determine the active UINavigationController where the user is. How can I determine this?
UITabBarController has a property called selectedViewController. Just check this for the appropriate value (e.g. by checking its class or a tag of its main view).
I figured it out on my own.
I just used this code to make my code work. It may seem a bit far from my original question but this made it to work as I just simply want to display my custom notification view on my current view.
if (self.tabBarController.selectedIndex == 0)
{
[self displayNotificationWhenOnline:self.navController1.visibleViewController.view];
}
else if (self.tabBarController.selectedIndex == 1)
{
[self displayNotificationWhenOnline:self.navController2.visibleViewController.view];
}
You can get perticuler view controller using this code,
[(UINavigationController*)[[(AppDelegate*)[[UIApplication sharedApplication]delegate] tabBarController] selectedViewController]visibleViewController]
Say I have two view controllers: xVC and yVC. I have used the shake API and and have used the methods -(void)motionBegan,-(void)motionEnded: and -(void)motionCancelled in xVC. What happens is when the device is shaken, it fires a simple animation. Now the thing is that this animation is fired even when the I have yVC open that is, when yVS.view has been added as the subview. What I am looking for is some if condition which I can use in -(void)motionEnded: like this:
if(yVC == nil)
{
//trigger animation
}
By that I mean that the shake shouldn't work when yVC is visible. How do I do that? Please help.
The general advice I have seen and used is to ask a view if it has a non-nil window property:
if( ! yVC.view.window) {
// trigger animation
}
But note that this doesn't always equate with being visible; though in most apps it's about as good as you can performantly get (the basic case where it's not accurate is when a different view completely obscures it, but this may still satisfy your needs)
Add this to both of your view controllers:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
visible = YES;
}
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
visible = NO;
}
Now, just check the variable isVisible of both the view controllers and trigger your animation likewise.
The previous answers all work to some degree, but fail to take modally presented view controllers into account. If view controller A presents view controller B, of the previous answers will tell you that A is still visible. If you, like me, want to know whether or not the view is actually visible (and not just a part of the view hierarchy), I would suggest also checking the presentedViewController property:
if (self.isViewLoaded && [self.view window] && !self.presentedViewController) {
// User is looking at this view and nothing else
}
This works since presentedViewController will be non-nil whenever the current view controller OR any of its ancestors are currently presenting another view controller.
I have an app which has split view inside a tab bar, and these split views often have navigation hierarchy and then sometimes modal views are presents on top of them, and it all works fine, but...
I am trying to display a passcode lock whenever the app goes into background, so I put
[self.window.rootViewController presentModalViewController:lockView animated:YES];
in my AppDelegate's method
- (void)applicationWillResignActive:(UIApplication *)application
...which works fine unless a modal view is displayed.
the passcode does not display if a modal view is open.
Is there a way to retrieve the currently active view controller so I can present this lock view?
Thanks in advance
Cheerio
Code that worked was as follows:
BOOL hasKids = YES;
UIViewController *topViewController = (UIViewController*)[[(UITabBarController*)self.window.rootViewController viewControllers] objectAtIndex:((UITabBarController*)self.window.rootViewController).selectedIndex];
while (hasKids) {
if (topViewController.presentedViewController) {
hasKids = YES;
topViewController = topViewController.presentedViewController;
} else {
hasKids = NO;
}
}
[topViewController presentModalViewController:lockView animated:YES];`
I think the easiest way is to keep track of which tab is currently active (there are a number of ways to do this, but I'd recommend implementing the UITabBarControllerDelegate and handling its tabBarController:didSelectViewController: method).
Once that's done, you'll probably need to manage a property in each view controller that holds any modal view controllers you present. If, however, you're on iOS 5 or higher, look into the UIViewController property presentedViewController. It appears that this is a new way to do exactly what you want.
I have an issue with the UIPageControl. I simplified the issue for clarity below:
I put a button and a UIPageControl in my app with Interface builder and put the following in the code:
- (IBAction)tappedButton:(id)sender{
self.pageControl.currentPage = 3;
NSLog(#"Tapped Button");
}
- (IBAction)changePage:(id)sender{
NSLog(#"PAGE Changed!!!!");
}
I attached the Value Changed action to the pageController via Interface Builder.
When I tap on the button, I see the output "Tapped Button" and the third dot is highlighted... but the changePage method is never called.
Any ideas?
The changePage: method will only be called when the users request a change of page using the UIPageControl. It won't be called when the user taps the button. If you want to call the changePage: method when the button is pressed called it explicitly:
[self changePage: nil];
UIPageControl doesn't actually change pages for you. You have to write that code, inresponse to the valueChanged event. So, you want to connect that event of your UIPageControl object to your output (tappedButton: I guess), and then call your changePage: method to actually change the UI. Does that help?
There are some example projects referenced from the Apple docs that use UIScrollView and UIPageControl together. Check 'em out.