Getting reference to the top-most view/window in iOS application - objective-c

I'm creating a reusable framework for displaying notifications in an iOS application. I'd like the notification views to be added over the top of everything else in the application, sort of like a UIAlertView. When I init the manager that listens for NSNotification events and adds views in response, I need to get a reference to the top-most view in the application. This is what I have at the moment:
_topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
Would this work for any iOS application or is their a safer/better way to get the top view?

Whenever I want to display some overlay on top of everything else, I just add it on top of the Application Window directly:
[[[UIApplication sharedApplication] keyWindow] addSubview:someView]

There are two parts of the problem: Top window, top view on top window.
All the existing answers missed the top window part. But [[UIApplication sharedApplication] keyWindow] is not guaranteed to be the top window.
Top window. It is very unlikely that there will be two windows with the same windowLevel coexist for an app, so we can sort all the windows by windowLevel and get the topmost one.
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
Top view on top window. Just to be complete. As already pointed out in the question:
UIView *topView = [[topWindow subviews] lastObject];

Usually that will give you the top view, but there's no guarantee that it's visible to the user. It could be off the screen, have an alpha of 0.0, or could be have size of 0x0 for example.
It could also be that the keyWindow has no subviews, so you should probably test for that first. This would be unusual, but it's not impossible.
UIWindow is a subclass of UIView, so if you want to make sure your notification is visible to the user, you can add it directly to the keyWindow using addSubview: and it will instantly be the top most view. I'm not sure if this is what you're looking to do though. (Based on your question, it looks like you already know this.)

Actually there could be more than one UIWindow in your application. For example, if a keyboard is on screen then [[UIApplication sharedApplication] windows] will contain at least two windows (your key-window and the keyboard window).
So if you want your view to appear ontop of both of them then you gotta do something like:
[[[[UIApplication sharedApplication] windows] lastObject] addSubview:view];
(Assuming lastObject contains the window with the highest windowLevel priority).

I'm sticking to the question as the title states and not the discussion. Which view is top visible on any given point?
#implementation UIView (Extra)
- (UIView *)findTopMostViewForPoint:(CGPoint)point
{
for(int i = self.subviews.count - 1; i >= 0; i--)
{
UIView *subview = [self.subviews objectAtIndex:i];
if(!subview.hidden && CGRectContainsPoint(subview.frame, point))
{
CGPoint pointConverted = [self convertPoint:point toView:subview];
return [subview findTopMostViewForPoint:pointConverted];
}
}
return self;
}
- (UIWindow *)topmostWindow
{
UIWindow *topWindow = [[[UIApplication sharedApplication].windows sortedArrayUsingComparator:^NSComparisonResult(UIWindow *win1, UIWindow *win2) {
return win1.windowLevel - win2.windowLevel;
}] lastObject];
return topWindow;
}
#end
Can be used directly with any UIWindow as receiver or any UIView as receiver.

If you are adding a loading view (an activity indicator view for instance), make sure you have an object of UIWindow class. If you show an action sheet just before you show your loading view, the keyWindow will be the UIActionSheet and not UIWindow. And since the action sheet will go away, the loading view will go away with it. Or that's what was causing me problems.
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:#"UIWindow"]) {
// find uiwindow in windows
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
if ([NSStringFromClass([window class]) isEqualToString:#"UIWindow"]) {
keyWindow = window;
break;
}
}
}

If your application only works in portrait orientation, this is enough:
[[[UIApplication sharedApplication] keyWindow] addSubview:yourView]
And your view will not be shown over keyboard and status bar.
If you want to get a topmost view that over keyboard or status bar, or you want the topmost view can rotate correctly with devices, please try this framework:
https://github.com/HarrisonXi/TopmostView
It supports iOS7/8/9.

Just use this code if you want to add a view above of everything in the screen.
[[UIApplication sharedApplication].keyWindow addSubView: yourView];

try this
UIWindow *window = [[[UIApplication sharedApplication] windows] lastObject];

UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
if (![NSStringFromClass([keyWindow class]) isEqualToString:#"UIWindow"]) {
NSArray *windows = [UIApplication sharedApplication].windows;
for (UIWindow *window in windows) {
if ([NSStringFromClass([window class]) isEqualToString:#"UIWindow"]) {
keyWindow = window;
break;
}
}
}

Related

Open NSMenu from NSButton with storyboard

Without storyboard this code works perfectly. It opens NSMenu
-(IBAction)openExportCompletePaletteMenu:(id)sender {
NSPoint point = [self.window convertRectToScreen:((NSButton*)sender).frame].origin;
[self.menu popUpMenuPositioningItem:nil atLocation:point inView:nil];
}
With storyboard in a ViewController obviously I changed self.window whit:
[[NSApplication sharedApplication].windows objectAtIndex:0]
or
[[NSApplication sharedApplication] mainWindow]
but doesn't seem right choices. Is it possible that with storyboard this is no longer possible? This sounds bad.
You get the parent window of a view controller in a storyboard with
self.view.window;

Custom segue, but leave the previous scene showing

Imagine a custom segue ...
-(void)perform
{
UIView *sv = ((UIViewController *)self.sourceViewController).view;
UIView *dv = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dv aboveSubview:sv];
[dv coverFromRight:0 then:^
{
[self.sourceViewController
presentViewController:self.destinationViewController
animated:NO completion:nil];
}];
}
Which in fact, only PARTIALLY (!) covers the "underneath, previous" scene,
and in fact DOES NOT call "presentViewController", so, the "underneath, previous" scene in fact keeps operating normally.
-(void)perform
{
UIView *sv = ((UIViewController *)self.sourceViewController).view;
UIView *dv = ((UIViewController *)self.destinationViewController).view;
UIWindow *window = [[[UIApplication sharedApplication] delegate] window];
[window insertSubview:dv aboveSubview:sv];
[dv coverButOnlyHalfWay:0 then:^
{
}];
}
Essentially, is this possible?
In fact, I've found from experiment the above works (!!). BUT when you come to the custom unwind segue, it does not work: everything crashes. (Perhaps as you'd expect.)
What's the situation? is there a way to make a custom segue, which, covers only say half the "original, underneath" scene and leaves that scene running?
(I appreciate you can just implement this using a container view, but it's not as clean as a whole segue scene.)
Why use a segue? You can just add your view as a subview and position it correct using CGRectMake, this would be much easier.
// Size Your View with X, Y coordinates
[viewController.view setFrame:CGRectMake(0, 0, 320, 192)];
[self.view addSubview:viewController.view];
[viewController didMoveToParentViewController:self];
[self addChildViewController:viewController];

Second UIWindow Not Displaying (iPad)

I am attempting to create two UIWindows because I would like two UINavigationControllers on screen at the same time on my app. I initialize two windows in my app delegate but only one window's view is displayed. Does anyone know why this is so?
Here is the code I used:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
UIViewController * controller1 = [[UIViewController alloc] init];
[controller1.view setBackgroundColor:[UIColor grayColor]];
UINavigationController * nav1 = [[UINavigationController alloc] initWithRootViewController:controller1];
[window addSubview:nav1.view];
[window makeKeyAndVisible];
UIWindow * window2 = [[UIWindow alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
UIViewController * controller2 = [[UIViewController alloc] init];
[controller2.view setBackgroundColor:[UIColor yellowColor]];
UINavigationController * nav2 = [[UINavigationController alloc] initWithRootViewController:controller2];
[window2 addSubview:nav2.view];
[window2 makeKeyAndVisible];
NSLog(#"%#", [[UIApplication sharedApplication] windows]);
return YES;
}
The gray from the first window is visible, but the yellow from the second is not. The output from this is:
"<UIWindow: 0x591e650; frame = (0 0; 768 1024); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x591e7a0>>",
"<UIWindow: 0x5923920; frame = (0 0; 100 100); layer = <CALayer: 0x59239a0>>"
which means the second window is created and added to the application, but just not displayed. Does anyone know why this is so?
Thanks in advance!
The two UIWindow's windowLevel property is equal, they are all UIWindowLevelNormal.
If you want the second UIWindow display font of the first UIWindow, You should set the second UIWindow's windowLevel value bigger. Like:
window2.windowLevel = UIWindowLevelNormal + 1;
PS:
[window makeKeyAndVisible];
...
[window2 makeKeyAndVisible];
There is only one keyWindow at a time, The key window is the one that is designated to receive keyboard and other non-touch related events. Only one window at a time may be the key window.
Just use a UISplitViewController.
Or try MGSplitVIewController if you need to customization. It might have what you need.
I've discovered how to get the second UIWindow to display. You must set the clipsToBound property to YES. Otherwise, the view from one of the windows will completely cover the other view. The two windows were properly added and visible after all.
This might be a really old post but I just run into the same problem. Some coding mistakes where already answered but the main issue we have here is how you instantiating the UIWindow.
Here is a Swift example how to display another UIWindow correctly.
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow? = UIWindow(frame: UIScreen.mainScreen().bounds)
let newWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
// save a reference to your Window so it won't be released by ARC
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window!.rootViewController = SomeViewController()
self.window!.makeKeyAndVisible()
// in your example you have created the window inside this method,
// which executes correctly and at the end of this method just releases the window,
// because you never saved the reference to the window
self.newWindow.rootViewController = SomeOtherViewController()
self.newWindow.windowLevel = UIWindowLevelStatusBar + 1.0
self.newWindow.hidden = false
return true
}
}
Btw. you don't have to create a UIWindow in AppDelegate. It depends on your code behavior.
try this code...
id delegate = [[UIApplication sharedApplication] delegate];
[[delegate FirstView] presentModalViewController:SecondView animated:YES];

How to get the active view in an iOS application from the app delegate?

how can i get the currently active view (the main view currently being viewed by the user) from the app delegate for references sake?
UIWindow *window = [[UIApplication sharedApplication] keyWindow];
UIView *topView = window.rootViewController.view;
All top answers doesn't work with modal presented views!
Use this code instead:
UIView * topView = [[[[UIApplication sharedApplication] keyWindow] subviews] lastObject];
It depends on how your app is set up.
Typically, your app delegate will have a main view controller property that will let you get to it.
To get your app delegate
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
UIView *topView = appDelegate.viewController.view;
If your app has a navigation controller property in the app delegate you can do something like this.
UIView *topView = appDelegate.navigationController.topViewController.view;
I found this and it works great for me for all types of segues and view controllers.
+(UIViewController*) getTopController{
UIViewController *topViewController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
}
return topViewController;
}
you can use [appDelegate.navigationController.topViewController class] to log the class of the controller or get the title property to know which one it is.
Hope this helps you
UINavigationController *navCnt = (UINavigationController *)self.window.rootViewController;
if([navCnt.topViewController isMemberOfClass:[WebViewController class]])
{
return UIInterfaceOrientationMaskAll;
}
else
return UIInterfaceOrientationMaskPortrait;
Anywhere in the app you can get your rootViewController View also like that:
id<UIApplicationDelegate> appDelegate = [[UIApplication sharedApplication] delegate];
UIView *rootView = appDelegate.window.rootViewController.view;
Try Eric's answer:
+ (UIViewController*) topMostController
{
UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;
while (topController.presentedViewController) {
topController = topController.presentedViewController;
}
return topController;
}

Easy way to dismiss keyboard?

I have quite a few controls scattered throughout many table cells in my table, and I was wondering if there's an easier way to dismiss the keyboard without having to loop through all my controls and resigning them all as the first responder. I guess the question is.. How would I get the current first responder to the keyboard?
Try:
[self.view endEditing:YES];
You can force the currently-editing view to resign its first responder status with [view endEditing:YES]. This hides the keyboard.
Unlike -[UIResponder resignFirstResponder], -[UIView endEditing:] will search through subviews to find the current first responder. So you can send it to your top-level view (e.g. self.view in a UIViewController) and it will do the right thing.
(This answer previously included a couple of other solutions, which also worked but were more complicated than is necessary. I've removed them to avoid confusion.)
You can send a nil targeted action to the application, it'll resign first responder at any time without having to worry about which view currently has first responder status.
Objective-C:
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
Swift 3.0:
UIApplication.shared.sendAction(#selector(resignFirstResponder), to: nil, from: nil, for: nil)
Nil targeted actions are common on Mac OS X for menu commands, and here's a use for them on iOS.
To be honest, I'm not crazy about any of the solutions proposed here. I did find a nice way to use a TapGestureRecognizer that I think gets to the heart of your problem: When you click on anything besides the keyboard, dismiss the keyboard.
In viewDidLoad, register to receive keyboard notifications and create a UITapGestureRecognizer:
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(keyboardWillShow:) name:
UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:#selector(keyboardWillHide:) name:
UIKeyboardWillHideNotification object:nil];
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(didTapAnywhere:)];
Add the keyboard show/hide responders. There you add and remove the TapGestureRecognizer to the UIView that should dismiss the keyboard when tapped. Note: You do not have to add it to all of the sub-views or controls.
-(void) keyboardWillShow:(NSNotification *) note {
[self.view addGestureRecognizer:tapRecognizer];
}
-(void) keyboardWillHide:(NSNotification *) note
{
[self.view removeGestureRecognizer:tapRecognizer];
}
The TapGestureRecognizer will call your function when it gets a tap and you can dismiss the keyboard like this:
-(void)didTapAnywhere: (UITapGestureRecognizer*) recognizer {
[textField resignFirstResponder];
}
The nice thing about this solution is that it only filters for Taps, not swipes. So if you have scrolling content above the keyboard, swipes will still scroll and leave the keyboard displayed. By removing the gesture recognizer after the keyboard is gone, future taps on your view get handled normally.
This is a solution to make the keyboard go away when hit return in any textfield, by adding code in one place (so don't have to add a handler for each textfield):
consider this scenario:
i have a viewcontroller with two textfields (username and password).
and the viewcontroller implements UITextFieldDelegate protocol
i do this in viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
username.delegate = self;
password.delegate = self;
}
and the viewcontroller implements the optional method as
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
and irrespective of the textfield you are in, as soon as i hit return in the keyboard, it gets dismissed!
In your case, the same would work as long as you set all the textfield's delegate to self and implement textFieldShouldReturn
A better approach is to have something "steal" first responder status.
Since UIApplication is a subclass of UIResponder, you could try:
[[UIApplication sharedApplication] becomeFirstResponder]
[[UIApplication sharedApplication] resignFirstResponder]
Failing that, create a new UITextField with a zero sized frame, add it to a view somewhere and do something similar (become followed by resign).
Tuck this away in some utility class.
+ (void)dismissKeyboard {
[self globalResignFirstResponder];
}
+ (void) globalResignFirstResponder {
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
for (UIView * view in [window subviews]){
[self globalResignFirstResponderRec:view];
}
}
+ (void) globalResignFirstResponderRec:(UIView*) view {
if ([view respondsToSelector:#selector(resignFirstResponder)]){
[view resignFirstResponder];
}
for (UIView * subview in [view subviews]){
[self globalResignFirstResponderRec:subview];
}
}
#Nicholas Riley & #Kendall Helmstetter Geln & #cannyboy:
Absolutely brilliant!
Thank you.
Considering your advice and the advice of others in this thread, this is what I've done:
What it looks like when used:
[[self appDelegate] dismissKeyboard]; (note: I added appDelegate as an addition to NSObject so I can use anywhere on anything)
What it looks like under the hood:
- (void)dismissKeyboard
{
UITextField *tempTextField = [[[UITextField alloc] initWithFrame:CGRectZero] autorelease];
tempTextField.enabled = NO;
[myRootViewController.view addSubview:tempTextField];
[tempTextField becomeFirstResponder];
[tempTextField resignFirstResponder];
[tempTextField removeFromSuperview];
}
EDIT
Amendment to my answer to included tempTextField.enabled = NO;. Disabling the text field will prevent UIKeyboardWillShowNotification and UIKeyboardWillHideNotification keyboard notifications from being sent should you rely on these notifications throughout your app.
Quick tip on how to dismiss the keyboard in iOS when a user touches anywhere on the screen outside of the UITextField or keyboard. Considering how much real estate the iOS keyboard can take up, it makes sense to have an easy and intuitive way for your users to dismiss the keyboard.
Here's a link
A lot of overly-complicated answers here, perhaps because this is not easy to find in the iOS documentation. JosephH had it right above:
[[view window] endEditing:YES];
Here's what I use in my code. It works like a charm!
In yourviewcontroller.h add:
#property (nonatomic) UITapGestureRecognizer *tapRecognizer;
Now in the .m file, add this to your ViewDidLoad function:
- (void)viewDidLoad {
//Keyboard stuff
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapAnywhere:)];
tapRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:tapRecognizer];
}
Also, add this function in the .m file:
- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
[self.view endEditing:YES];
}
Even Simpler than Meagar's answer
overwrite touchesBegan:withEvent:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[textField resignFirstResponder];`
}
This will dismiss the keyboardwhen you touch anywhere in the background.
You should send endEditing: to working window being the subclass of UIView
[[UIApplication sharedApplication].windows.firstObject endEditing:NO];
In your view controller's header file add <UITextFieldDelegate> to the definition of your controller's interface so that it conform to the UITextField delegate protocol...
#interface someViewController : UIViewController <UITextFieldDelegate>
... In the controller's implementation file (.m) add the following method, or the code inside it if you already have a viewDidLoad method ...
- (void)viewDidLoad
{
// Do any additional setup after loading the view, typically from a nib.
self.yourTextBox.delegate = self;
}
... Then, link yourTextBox to your actual text field
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
{
if (theTextField == yourTextBox) {
[theTextField resignFirstResponder];
}
return YES;
}
The best way to dismiss keyboard from UITableView and UIScrollView are:
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag
In swift 3 you can do the following
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
Jeremy's answer wasn't quite working for me, I think because I had a navigation stack in a tab view with a modal dialog on top of it. I'm using the following right now and it is working for me, but your mileage may vary.
// dismiss keyboard (mostly macro)
[[UIApplication sharedApplication].delegate dismissKeyboard]; // call this in your to app dismiss the keybaord
// --- dismiss keyboard (in indexAppDelegate.h) (mostly macro)
- (void)dismissKeyboard;
// --- dismiss keyboard (in indexAppDelegate.m) (mostly macro)
// do this from anywhere to dismiss the keybard
- (void)dismissKeyboard { // from: http://stackoverflow.com/questions/741185/easy-way-to-dismiss-keyboard
UITextField *tempTextField = [[UITextField alloc] initWithFrame:CGRectZero];
UIViewController *myRootViewController = <#viewController#>; // for simple apps (INPUT: viewController is whatever your root controller is called. Probably is a way to determine this progragrammatically)
UIViewController *uivc;
if (myRootViewController.navigationController != nil) { // for when there is a nav stack
uivc = myRootViewController.navigationController;
} else {
uivc = myRootViewController;
}
if (uivc.modalViewController != nil) { // for when there is something modal
uivc = uivc.modalViewController;
}
[uivc.view addSubview:tempTextField];
[tempTextField becomeFirstResponder];
[tempTextField resignFirstResponder];
[tempTextField removeFromSuperview];
[tempTextField release];
}
You may also need to override UIViewController disablesAutomaticKeyboardDismissal to get this to work in some cases. This may have to be done on the UINavigationController if you have one.
Subclass your textfields... and also textviews
In the subclass put this code..
-(void)conformsToKeyboardDismissNotification{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(dismissKeyBoard) name:KEYBOARD_DISMISS object:nil];
}
-(void)deConformsToKeyboardDismissNotification{
[[NSNotificationCenter defaultCenter] removeObserver:self name:KEYBOARD_DISMISS object:nil];
}
- (void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[self resignFirstResponder];
}
In the textfield delegates (similarly for textview delegates)
-(void)textFieldDidBeginEditing:(JCPTextField *)textField{
[textField conformsToKeyboardDismissNotification];
}
- (void)textFieldDidEndEditing:(JCPTextField *)textField{
[textField deConformsToKeyboardDismissNotification];
}
All set.. Now just post the notification from anywhere in your code. It will resign any keyboard.
And in swift we can do
UIApplication.sharedApplication().sendAction("resignFirstResponder", to: nil, from: nil, forEvent: nil)
To dismiss a keyboard after the keyboard has popped up, there are 2 cases,
when the UITextField is inside a UIScrollView
when the UITextField is outside a UIScrollView
2.when the UITextField is outside a UIScrollView
override the method in your UIViewController subclass
you must also add delegate for all UITextView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES];
}
In a scroll view, Tapping outside will not fire any event, so in that case use a Tap Gesture Recognizer,
Drag and drop a UITapGesture for the scroll view and create an IBAction for it.
to create a IBAction, press ctrl+ click the UITapGesture and drag it to the .h file of viewcontroller.
Here I have named tappedEvent as my action name
- (IBAction)tappedEvent:(id)sender {
[self.view endEditing:YES]; }
the abouve given Information was derived from the following link, please refer for more information or contact me if you dont understand the abouve data.
http://samwize.com/2014/03/27/dismiss-keyboard-when-tap-outside-a-uitextfield-slash-uitextview/
I hate that there's no "global" way to programmatically dismiss the keyboard without using private API calls. Frequently, I have the need to dismiss the keyboard programmatically without knowing what object is the first responder. I've resorted to inspecting the self using the Objective-C runtime API, enumerating through all of its properties, pulling out those which are of type UITextField, and sending them the resignFirstResponder message.
It shouldn't be this hard to do this...
It's not pretty, but the way I resign the firstResponder when I don't know what that the responder is:
Create an UITextField, either in IB or programmatically. Make it Hidden. Link it up to your code if you made it in IB.
Then, when you want to dismiss the keyboard, you switch the responder to the invisible text field, and immediately resign it:
[self.invisibleField becomeFirstResponder];
[self.invisibleField resignFirstResponder];
You can recursively iterate through subviews, store an array of all UITextFields, and then loop through them and resign them all.
Not really a great solution, especially if you have a lot of subviews, but for simple apps it should do the trick.
I solved this in a much more complicated, but much more performant way, but using a singleton/manager for the animation engine of my app, and any time a text field became the responder, I would assign assign it to a static which would get swept up (resigned) based on certain other events... its almost impossible for me to explain in a paragraph.
Be creative, it only took me 10 minutes to think through this for my app after I found this question.
A slightly more robust method I needed to use recently:
- (void) dismissKeyboard {
NSArray *windows = [UIApplication sharedApplication].windows;
for(UIWindow *window in windows) [window endEditing:true];
// Or if you're only working with one UIWindow:
[[UIApplication sharedApplication].keyWindow endEditing:true];
}
I found some of the other "global" methods didn't work (for example, UIWebView & WKWebView refused to resign).
Add A Tap Gesture Recognizer to your view.And define it ibaction
your .m file will be like
- (IBAction)hideKeyboardGesture:(id)sender {
NSArray *windows = [UIApplication sharedApplication].windows;
for(UIWindow *window in windows) [window endEditing:true];
[[UIApplication sharedApplication].keyWindow endEditing:true];
}
It's worked for me
Yes, endEditing is the best option. And From iOW 7.0, UIScrollView has a cool feature to dismiss the keyboard on interacting with the scroll view. For achieving this, you can set keyboardDismissMode property of UIScrollView.
Set the keyboard dismiss mode as:
tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag
It has few other types. Have a look at this apple document.
In swift :
self.view.endEditing(true)
the easist way is to call the method
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if(![txtfld resignFirstResponder])
{
[txtfld resignFirstResponder];
}
else
{
}
[super touchesBegan:touches withEvent:event];
}
You have to use one of these methods,
[self.view endEditing:YES];
or
[self.textField resignFirstResponder];