I have a view controller with a text field. I'm trying to create an IBAction to dismiss they keyboard when user taps outside the text field by control-dragging from outside the text field in the Xib file to my .h file, but I don't get the option to choose "Action," only "Outlet" and "Outlet collection." I don't even get a window that asks me to choose when I control drag inside a *.m file. What am I missing?
I was able to do this in Xcode 4.
When you ctrl-drag from "outside the text field", you are most likely interacting with the top-level view of the view controller. This is a UIView object which does not have actions. Only views that inherit from UIControl have actions, e.g. buttons, text fields. This is not an XCode 4 vs 5 issue -- it's always been this way.
In your view controller, override touchesBegan:withEvent:. Make a call to [self.view endEditing] to dismiss the keyboard.
This is possible because your view controller inherits from the UIResponder class, as do UIViews. When the user touches something on the screen, the event gets passed up the responder chain, e.g. from subview to parent view to parent view controller etc., until one of those responders decides to respond to or purposefully discard that event. By overriding touchesBegan:withEvent:, your view controller can handle that event and do something meaningful (like dismiss the keyboard).
A simple solution would be using a simple UITapGestureRecognizer added to the "main" view.
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
gestureRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:gestureRecognizer];
Then the method hideKeyboard:
- (void)hideKeyboard
{
[[UIApplication sharedApplication] sendAction:#selector(resignFirstResponder) to:nil from:nil forEvent:nil];
} <br>
The tap is sent through views until it finds one that could manage it, like the view controller view that triggers the gesture.
Use this code on your .m file
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
selectedTextField = textField;
return YES;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[selectedTextField resignFirstResponder];
}
Related
Simple question that I'm currently having trouble as to how to get started.
I have a ViewController with multiple images/icons, and I would like to have new view controllers for each image/icon that is selected. I have a segue (show) from my initial view controller to my new one...but now how do I code it so when I click on a specific image it'll segue to the corresponding VC I want?
Thanks in advance!
If all of your Images/Links goes to one kind of ViewController, you can link it with segue in your interface builder and so you use just -performSegueWithIdentifier and seed it with your data or model corresponding to your ViewController.
For getting touch events and handling it, you can use delegate method which each subviews call their delegate when touch event catches. Assume below code for better imagination:
//Added in initiation of SubView
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureUpdated)];
//This function will be fired when gesture recognized
- (void)tapGestureUpdated {
if ([self.tapDelegate respondsToSelector:#selector(onItemTapped:)]) {
[self.tapDelegate onItemTapped:self.item];
}
}
But if you're showing to different types of ViewControllers, for each kind you should add segue and ViewControllers.
Superview will call next ViewController like this:
[self performSegueWithIdentifier:#"showNextViewControllerSegue" sender:self];
So there is such event chain for handling it:
UITapGestureRecognizer -> Your SubView -> Call it's delegate
(SuperView) -> Call next segue according to subView's type.
I am using simple Modal segues between view controllers and i it is not dismissing the keyboard. I tries [textField resignFirstResponder] on view will disappear method but still no luck.
I am not using any Navigation Controllers, just simple View Controllers.
I also tried doing this but still no luck. Need Help.
View Controller A ---------> View Controller B
in View controller B. I called [self disablesAutomaticKeyboardDismissal] in viewDidLoad.
and I've overridden in it like so
-(BOOl)disablesAutomaticKeyboardDismissal
{
return NO;
}
This one could help you too
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[self.view endEditing:YES];
}
With this, when you tap outside the textfield , the keyboard disappear
I made a custom split view controller, and I have tried to mimic the standard one as much as possible.
One feature I have is if the device is in portrait and the master view is displayed, if you tap on the details view, the master view will hide.
I use this code in the details view to accomplish this.
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
return [super hitTest:point withEvent:event];
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// Detect touches on the details View and notify the Split View controller
if(point.y != self.touchLocation.y)
{
if (_delegate && [_delegate respondsToSelector:#selector(detailsViewDidTapDetails:)])
[_delegate detailsViewDidTapDetails:self];
}
return [super pointInside:point withEvent:event];
}
The problem I am having, is if the detailsView is filled with a view that has its own navigation bar, then any buttons pressed in the navigation bar trigger the 'details view tapped' methods displayed above. This conflicts with adding the 'Show Details' button that you place inside a nav bar. Essentially what happens, is the methods to hide/show the master View is called twice back to back.
I need a way to ignore any taps on top of my 'hide/show details' button. I have a reference to the button, I just need to ignore taps on it within my hitTest / pointsInside methods.
I have a view controller whose view is setup in such a way that it has 3 buttons and other subviews. On clicking one of the buttons(3rd button), i am adding another view controller's view as subview to self.view (in this view i have a search display controller in the active state with keyboard)
I'm able to achieve this using the following code
[self.searchDisplayController setActive:YES];
[self.searchDisplayController.searchBar setShowsCancelButton:NO];
[self.searchDisplayController.searchBar becomeFirstResponder];
Now when i press the 2nd button, i try removing this view from the superview and also try to resign the keyboard in the viewWillDisappear ([self.view endEditing:YES]) in the following manner, but keyboard still doesnt resign
One small edit, it is resigning in case i comment out the following piece of code
- (BOOL)searchBarShouldEndEditing:(UISearchBar *)searchBar {
if (self.dataSource.count)
return YES;
return NO;
}
Try to resign UISearchBar in viewWillDisappear
[yourSearchBar resignFirstResponder];
Inside the method that is called to your 2nd button, just type in
[self.searchDisplayController.searchBar resignFirstResponder];
Leave the viewWillDisappear alone. That is for when the view is done with whatever animation it is doing, and when the view is leaving. If you set the display controller to resigning the responder, it should make it go away immediately.
Hope this helps!
you can do it using NSNotificationCenter as below.
//.m file:
[[NSNotificationCenter defaultCenter]addObserver:self
selector:#selector(ResignFirstResponder:) name:#"resign" object:nil];
in ResignFirstResponder:
[searchBar resignFirstResponder];
in which class you use above addObserver, you have to implement that method.
//.m file from where you want to send action, call method as below. [on your second button click]
[[NSNotificationCenter defaultCenter] postNotificationName:#"resign"
object:nil];
Newest Update: I created a brand new project that is built the exact same way as below. However, this test project actually works just fine even though it seems to be the same... One thing I've noticed is that the parent view controller in the broken version is receiving the -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event when clicking on the child view controller's view... In the working version, the child view controller receives the event as it should... It's as if the parent view is blocking the child view or something..?
Progress Update: Upon screwing around a bit I have found that it works fine when directly assigning a frame to the child view controllers. However, I have to create my project using autolayout so that is what I've done. For some reason, autolayout is causing the child view controller's view to be unresponsive...
At the moment I have a viewcontroller which has just 1 childviewcontroller.
The childviewcontroller's view shows up just fine but I cannot interact with the childViewController at all.
The childViewController has a couple of UIButtons but they do not respond to clicks.
I tried testing with this in both the parent and child viewcontrollers.
(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Touched!");
}
When clicking in the frame of the child view controller's view, this method responds in the parent view controller but not the child view controller.
The child view controller also works correctly when directly creating it and setting it as the root view controller in the app delegate.
The code I'm using in the parent view controller:
(void) viewDidLoad
{
[super viewDidLoad];
self.detailPageVC = [[GoalDetailsPageViewController alloc] init];
[self.view addSubview:self.detailPageVC.view];
[self addChildViewController:self.detailPageVC];
[self.detailPageVC didMoveToParentViewController:self];
}
Thanks for helping out a rookie! :)
the actual problem was in my GoalDetailsPageViewController. The issue was actually caused by trying to use autolayout within a uiscrollview... a tricky thing. Anyways, the original code I posted is fine, thanks.
Well, I can only suggest the following:
Make sure the userInteractionEnabled property of your buttons and the child ViewController's view is set to YES.
Double check that your view is not 'hidden' nor has an alpha of 0.0.
Confirm the exclusiveTouch of your partent ViewController's view is not set to YES.
Hope this helps!
My solution:
- (void) displayContentController: (UIViewController*) content{
[content.view setFrame:recorderView.bounds];
UINavigationController *childNavController = [[UINavigationController alloc] initWithRootViewController:content];
childNavController.toolbarHidden = NO;
childNavController.view.frame = content.view.frame;
[self addChildViewController:childNavController];
[recorderView addSubview:childNavController.view];
[childNavController didMoveToParentViewController:self];
}