My situation goes as follows: I have an app which has a PIN screen implemented. Its nothing high-tech just basic 4 UITextFields and implemented logic via UITextFieldDelegate - it works.
I'm showing this screen in app delegate on -(void)applicationWillEnterForeground:(UIApplication *)application event. I am using MMDrawerController from github (link: https://github.com/mutualmobile/MMDrawerController) as the main view controller. If the current view presented when the application enters background and foreground again is this MMDrawerController then the becomeFirstResponder is not working - it doesn't show the keyboard. If there is another view controller presented on top of drawer controller the when entering foreground (let's say settings view) then keyboard appears normally.
I have tried NSLoging the canBecomeFirstResponder property and its set to YES. What is going on? How to fix this?
I can paste code if needed but its nothing ambiguous. Just plain call becomeFirstResponder.
EDIT:
To explain things a bit more clearly. rootViewController is a view controller caleed LoginViewController and it alloc-inits the sidebar and the center view controllers, alloc-inits the drawer controller and hooks everything up so it works. The app delegate view is actually a PIN screen which pops up when the app enters foreground. Now the keyboard appears like it should for the first time the drawer is visible.
When the user pops up SettingsViewController (yes, this is another view controller accessible from the sidebar view controller) it works as well. But when the user dismisses the settings view controller keyboard doesn't appear anymore. It has to do something with the drawer cause I tried without it and it worked (but I only had sidebar or center view controller visible).
Ideally you would want to access the textField within the MMDrawerControllers currentView. I have achieved something similar with this implementation:
In your app delegate store a reference to the DrawerController like so:
In AppDels interface:
#property(nonatomic, strong) MMDrawerController *appDrawController;
Then after you create the local drawer controller in didFinishLaunching (if you followed the setup instructions for this library):
self.appDrawController = drawerController;
In your applicationWillEnterForeground:
THECLASSTHATCONTAINSTHEPINVIEW *yourClass = self.appDrawController.centerViewController.childViewControllers[0];
Now you can access the public methods/properties, so:
[[yourClass pinEntryField] becomeFirstResponder];
Does this help at all ?
Related
I'm working with some pre-existing code and frankly I'm a bit lost.
My goal is to create a view that displays on the bottom half of the screen when the user RETURNS to the app. This view forces the user to re-enter their password as verification. I've been informed AppDelegate's applicationDidBecomeActive is a good place to handle this process. The issue I'm running into is that the top half of the screen needs to show the view the user was previously viewing before the application became inactive. What is the best way to do this?
What I've been trying to do:
I made a view controller called passwordVerificationViewController and made a corresponding XIB. In applicationDidBecomeActive I try:
UIViewController *myCurrentController = (UIViewController *)navigationController.visibleViewController;
verifyPasswordViewController = [[VerifyPasswordViewController alloc]
initWithNibName:#"VerifyPasswordViewController" bundle:nil];
[myCurrentController.view addSubview:verifyPasswordViewController.view];
This doesn't work. The reason it doesn't work is because navigationController.visibleViewController is not returning the viewController that is on the screen, as I intended it to. I've also tried navigationController.topViewController but it gives me the same results.
Also of note, all of the view controllers in the app are opened via presentViewController and are presented by a navigation controller. I have tried using the navigationController.presentedViewController property but this always returns null.
Would the way I'm doing it work if I could figure out how to get the correct reference to the current on screen view? Is there a better way I can accomplish my goal?
EDIT: Solved using Helge Becker's method. Perhaps not the cleanest way, but I set up the notification center like he suggested. Then I wrapped my notificationHandler in an if statement with the condition, (self.isViewLoaded && self.view.window) as a means to see if the view controller is visible on the screen.
Post a notification in the app delegate methods.
Let the viewcontrollers then register for the notification.
That will allow all viewcontroller respnd to any qpp condition change.
Usualy became active and will enter background are suffice.
I have an iPad app with a UISplitviewController set as the root view controller of UIWindow. The master view controller (i.e. the view controller of the left view) is the UISplitViewController's delegate with the delegate method shouldHideViewController returns YES, this means when the app first launches the left view will be hidden and can be shown (and hidden) by the user gesture, i want to show the master view when i navigate to detail pages and prevent the user from hiding it using the gesture, i've tried to call shouldHideViewController method on the delegate to let it returns NO the second time it got called but this time it has no effect, the master view keeps hidden in detail pages and can be shown with the user gesture.
any ideas to achieve showing of the master view with this scenario would be highly appreciated.
This may only be a partial answer because I'm not sure what you mean that you call shouldHideViewController method on the delegate. My understanding is that only the UISplitView should call this method. If you call it, then it will not effect the UISplitView, because it wasn't what made the call. In other words, the delegate method is used by UISplitView to get some information (and allow you a place to do additional things to other stuff) but it is not used as a way to tell the UISplitView what to perform.
Having said that, at least for the gesture activation/deactivation, I would think that in splitViewController:shouldHideViewController:inOrientation: you could do something like
[svc setPresentsWithGesture:NO];
I don't see any way to programmatically tell the UISplitViewController to display or hide the master view controller because the delegate only tells it if it should proceed in presenting or hiding the master when it is going to try and do that. It does seem like there should be a way to do this though.
I'm working on a problem where I have a ViewController which opens a popOver when a button is pressed and then in the popOver you can edit some settings which affect the content shown in the mother ViewController (for instance change the color of the View, change a map or a table there). This can be off course called whenever the popOver is dismissed, but it needs to be live up-to-date.
I tried using delegates, where I can pass over data or call a function but the function won't be started on a ViewController wchich isn't active, right?
I also tried NSNotifications but it didn't work either.
I found several questions like this on stackoverflow, but there is no real answer yet:
UIPopoverController button selecting method of another ViewController but not updating its view iOS
Refresh the view controller from popover
Refreshing a view from a popover
Refresh a WebView in a ViewController from another ViewController
how to refresh or reload a uiviewcontroller
Can somebody please explain a generall way with some code snippets how to get this fixed?
Delegation is a fine solution. The target view controller is presumably still visible underneath the popover (which shouldn't fill the screen). In this case when the target receives the delegate callback it can do any updates and refresh its views to update the UI without any limitation. In this situation both view controllers (the 'target' and the popover) would both be classed as 'active' as they are both visible on screen.
I have to support down to iOS 4.3.
My app outputs in the console :
Using two-stage rotation animation. To use the smoother single-stage animation, this application must remove two-stage method implementations.
As far as I know I'm not using two-staged rotation. I just have this method in my view controllers :
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
What else should I check in order to fix that?
Edit:
More precisions: my app uses a UITabbarController subclass. When the app starts, it checks if a user is logged in and then initiates the controllers of the tabbar controller if it's the case. If there's no user logged in, a modal view is presented (from the tabbar controller) the prompt the user to login and the controllers of the tabbar controller aren't initialized (yet). The "two-staged rotation" error is shown only at that moment and the rotation doesn't work.
So to summarize, the problem happens in that situation:
The rootViewController of the main window is the tabbar controller
The tabbar controller is empty (there are no view controller in the tabs and there's no tab)
A view controller is modally presented from the tabbar controller
OK I found a solution.
It seems like the presented modal view won't rotate until the viewControllers property of the UITabBarController is initialized. Since the concerned modal view is actually for login, I don't want to display anything behind it until the user is logged in because the views intended to be hold by the tabbar controller depend on the fact that a user is logged in.
So now just before presenting the modal view, I initialize the tabbar controller with a single, empty UIViewController and I remove it when the modal view is dismissed (i.e. a user logged in).
Perhaps it seems like a hack but it works well. And even if I don't understand why, it doesn't seem completely illogical that the tabbar controller doesn't behave like we want until it is fully initialized.
If someone has a better solution or explanation, feel free to comment :)
There aren't many posts regarding this error, so I'll admit my own shortcomings for the benefit of the next person so focused on the trees they might miss the forest. I found a missing
[super viewWillAppear:animated];
call inside my sub.
I'm developing an iPad app that launches in landscape mode.
The first screen displays a UISplitViewController and my issue is that altough the app is in landscape mode the delegate is notified on splitViewController:willHideViewController:withBarButtonItem:forPopoverController: despite that the documentation states that:
When the split view controller rotates
from a landscape to portrait
orientation, it normally hides one of
its view controllers. When that
happens, it calls this method to
coordinate the addition of a button to
the toolbar (or navigation bar) of the
remaining custom view controller. If
you want the soon-to-be hidden view
controller to be displayed in a
popover, you must implement this
method and use it to add the specified
button to your interface.
As the app is in landscape mode and not transitioning to portrait I don't get why my delegate is notified. Why is it so?
valentin, to directly answer "why is it so?", i think the answer is simply that it's a bug in the implementation of their API.
as you seem to have found, when in landscape orientation, it calls the above when it sort of seems that it shouldn't, and then calls splitViewController:willShowViewController:invalidatingBarButtonItem: .
also, i discovered that when in portrait orientation, it sends a very early message (i.e. before the view.frame has been adjusted) to splitViewController:willHideViewController:withBarButtonItem:forPopoverController: .
the one thing i saw that annoyed me the most was that, using the code provided from their template creation, the button bar would appear and then disappear at startup.
my solution was to implement a workaround, which i have posted on git#github.com:johnkdoe/freeforall.git in the class KludgeWorkaroundForBuggySplitViewDelegateStartup .
make this a superclass of your current detail view controller class, as in
//#interface MyViewController : UIViewController<UISplitViewControllerDelegate>
#interface MyViewController : KludgeWorkaroundForBuggySplitViewDelegateStartup
this will set the initial button bar title to Master if you don't have something you prefer. you can override this by overriding the #property getter in your subclass implementation. if you want to do more than what's in this kludgeWorkaround class, you can override these yourself and (either copy and paste or) call [super ...] on them prior to doing your own work.
i can't say this solves the problem of what appears to me to be an implementation bug, but the workaround gets rid of the brief appearance of the button bar at startup of a split-view-controller app in landscape mode.