I have a UIView with multiple text boxes. Now i have used delegates to change the responder from from text field to another. In this case my key board goes away when the user comes to last text field.
but now i want to hide my key board when the user touches UIView(touches any where on screen apart from text boxes). Can some one help me with this.
Thanks
Use resignFirstResponder in touchesBegan, like so:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
if(touch.phase == UITouchPhaseBegan) {
[self.myTextField resignFirstResponder];
}
}
You may need to call this on multiple text fields if you're not sure where the focus is currently located; I haven't tested that case.
Additionally, in Interface Builder, you'll need to enable the "User Interaction Enabled" checkbox for the view, or programatically use:
myView.userInteractionEnabled = YES;
Just call this in your view controller when you want to hide the keyboard.
[self.view endEditing:NO];
I use
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if(touch.phase==UITouchPhaseBegan){
//find first response view
for (UIView *view in [self.view subviews]) {
if ([view isFirstResponder]) {
[view resignFirstResponder];
break;
}
}
}
}
According to Beginning iPhone Development, you draw a round rect button so that it covers your entire UI; the complete screen. Then go to the Layout menu and click Send to Back. Then in the inspector, change the button's type from round rect to Custom. Now add a touch up inside event to this button and attach it to a method which handles it. Within the body of this method, make sure you have the statements:
[myTextFieldOne resignFirstResponder];
[myTextFieldTwo resignFirstResponder];
Basically send the resignFirstResponder message to each of your text fields, or any field that can produce a keyboard.
I'm actually really new to the iPhone SDK. I don't know if this is the best method, but it works and it's what I learned from the aforementioned book. Hope it helps.
A super easy way to do this is working on what PCheese said.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
if(touch.phase == UITouchPhaseBegan) {
[self.view endEditing:YES];
}
}
I previously used [self.view endEditing:YES]; for a button event, but when combined with the previous answer it works a treat. Much easier, and you don't have to do anything else - just put it in your .m file. Also, this works with all (at least, as far as I have seen) text fields (works for UITextField and UITextView).
I know OP probably won't still need this but I just want to share it for others with the same problem.
Thanks Blaenk, I was trying to work out how to do this and didn't realise I could put a button in the background, nice trick! Here's my contribution (new to this site and to Cocoa Touch so it may not be the most robust code ever, but it's working so far...):
I call this method from the touchUpInside event on my UIButton:
-(void)closeKeyboard:(id)sender {
UIView *theFirstResponder = [self findFirstResponder];
if (theFirstResponder) {
[theFirstResponder resignFirstResponder];
}
}
Where this loop finds the firstResponder:
- (UIView *)findFirstResponder {
UIView *firstResponderView = nil;
for (UIView *view in [self entryFields]) {
if ([view isFirstResponder]) {
firstResponderView = view;
break;
}
}
return firstResponderView;
}
It is dependent on each of the UITextField controls in the view having a tag assigned to them (again, can do that in Interface Builder).
My two cents anyway, though i'd better give something back!
SO I agonized over this and I figured it out..
you don't need the other button or anything.
All you need to do is select "Files owner", in the inspector drag from its textField outlet (or whatever you named it) to your actual textfield (via whatever you named it) This will be in addition to whatever inputs you already had wired up.
and ofcourse in addition to the Control outlet (UIview changed to UIControl via inspector) to files owner via backgroundtouched...the first thing we all tried
it work for me
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:NO];
}
only need into self.view have an UItextField
http://objdev.com/2013/11/Dismissing-iOS-Keyboard-Self-View-EndEditing
The most appropriate way of solving this problem is using the following method:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if(![touch.view isMemberOfClass:[UITextField class]]) {
[touch.view endEditing:YES];
}
}
Note: This does not work on UIScrollView instances.
Change the class UIView to class UIControl from the identify tab of inspector.
Add this:
- (IBAction)tabBackground:(id) sender;
to your .h file.
Add this to your .m file:
- (IBAction)tabBackgroup:(id) sender {
[nameField resignFirstRespnder];
[numberField resignFirstResponder];
}
Connect your tabBackground from the inspector, action received section to the UIView (which is an an UIControl) and you're good to go.
For swift 4.0
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if touch?.phase == UITouchPhase.began {
touch?.view?.endEditing(true)
}
}
Related
I know there are lots of questions on multi finger touches and restrictions here and there,but none of them seem to work.All they suggest is to try setting exclusive touch and disable multi touch i.e.:
[self.view.subviews makeObjectsPerformSelector:#selector(setExclusiveTouch:) withObject:[NSNumber numberWithBool:YES]];
[self.view setMultipleTouchEnabled:NO];
Note: Initially when I used self.view.exclusiveTouch = NO; ,it didn't work for me.Mr.Hlung's comment in the 1st link provided some useful info of enabling the subviews exclusive touch through selector.
But they seem to work incomplete.I have a game view where there are multiple images on left and their corresponding images on the right.User has to drag the left image to the respective right image and match it.I am using UIPanGestureRecognizer to do so.Here comes a scenario which was the outcome of some rash testing by a tester in my office :)
When the user scrambles the images,i.e. plays awkwardly with all/few of his fingers,what happens is the frames are getting disturbed or few images overlap with one another.This is all because some where multiple touch is still available for user.Hence I want to eliminate that feature.I am also aware of the fact that there is a method called -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ,through which we can detect the number of user touches.What if I delete all user touches if the count is more than 1,i.e. if more than 1 finger touch is detected!!!
But I found no method to remove touches there,I also tried to assign last touch object to my image view through which I thought would ignore the rest of touches detected,i.e.:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([event allTouches].count>1)
{
UITouch *touch = [[touches allObjects] lastObject];
self.dragObjectImageView = (UIImageView *)[touch view];
}
}
Even this doesn't seem to work.
EDIT-Setting Max and Min number of touches:
I have also set the pan gesture's max and min no of touches to 1 as well,i.e.:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view.subviews makeObjectsPerformSelector:#selector(setExclusiveTouch:) withObject:[NSNumber numberWithBool:YES]];
for(UIImageView *iView in self.movableArray){
if ([iView isMemberOfClass:[UIImageView class]]){
UIPanGestureRecognizer * recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
recognizer.minimumNumberOfTouches = 1;
recognizer.maximumNumberOfTouches = 1;
iView.multipleTouchEnabled = NO;
[iView addGestureRecognizer:recognizer];
[iView setUserInteractionEnabled:YES];
recognizer.delegate = self;
}
}
}
Tried another tactic of disabling user interaction for image if multiple touches are detected,but in vain!
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([event allTouches].count > 1)
{
for (UIView* view in self.view.subviews)
{
if ([view isKindOfClass:[UIImageView class]])
{
[view setUserInteractionEnabled:NO];
}
}
}
else
{
for (UIView* view in self.view.subviews)
{
if ([view isKindOfClass:[UIImageView class]])
{
[view setUserInteractionEnabled:YES];
}
}
}
}
Some people might say there can't be a case where user will use multiple fingers to play.But I was asked to fix the issue and a developer has to obey and respect the testers perspective as well.
Can some one please help me get rid of the problem.
Thanks every one in advance :)
Instead of setting exclusive touch to our own view,turning on the same for the subview or the view we assign to self.view worked,in my case it is...
[gameView.subviews makeObjectsPerformSelector:#selector(setExclusiveTouch:) withObject:[NSNumber numberWithBool:YES]];
Hope it helps some one,thanks :)
As per apple documentation for the property multipleTouchEnabled in UIView Class Reference
multipleTouchEnabled
Other views in the same window can still receive touch events when
this property is NO. If you want this view to handle multi-touch
events exclusively, set the values of both this property and the
exclusiveTouch property to YES.
I see in your code, you've set setExclusiveTouch to all subviews but setMultipleTouchEnabled only for the container view and not all image views. Add the following line before/after setting exclusive touch and single touch may work correctly.
[self.view.subviews makeObjectsPerformSelector:#selector(setMultipleTouchEnabled:) withObject:[NSNumber numberWithBool:NO]];
How can I make it so that while the user is playing on the joystick to move the character at the centre they can also touch the bottom right of the screen (the second touch) to fire the gun? I have looked at other questions but I still cant figure it out...
this is basically the code....:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
//make the touch point...
UITouch *touch = [[event allTouches]anyObject];
CGPoint point = [touch locationInView:touch.view];
if (//touching a certain area (on the joystick)) {
//do stuff
}
else if (point.x > 300 && point.y > 200) {
/fire method
}
}
so basically how do I call touchesBegan again to find the position of CGPoint point, and work out if the fire method should be called?
Thanks
EDIT:
I have tried to do that 2nd option and done this:
in view controller.h I added:
#interface fireView: UIView
#end
and in .m I added:
#implementation fireView -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"hi");
}
#end
....but it doesn't log/print "hi"?
Use 2 UIGestureRecognizers. You can create 2 invisible views of needed size - one for joystick and one for fire button. For every view use single gesture recognizer. And then you will be able to handle taps on these view by in different methods without checking if it was fire or joystick.
Let's think you have 2 views - joystickView and fireView already. Then do it like
UITapGestureRecognizer* fireTapGestureRec= [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(fireTapped:)];
fireTapGestureRec.delegate = self;
fireTapGestureRec.numberOfTapsRequired = 1;
fireTapGestureRec.numberOfTouchesRequired = 1;
[fireView addGestureRecognizer:fireTapGestureRec];
[fireTapGestureRec release];
and write fireTapped: to handle the event. And the same thing for joystick.
EDIT
Second option (suggested in comments)
Make subclasses of UIView, like
#interface fireView: UIView
#interface joystickView: UIView
and for each subclass write it own touchesBegan: or touchesEnded:
I'm trying to figure out how to do something perhaps slightly non-standard. I have a view controller (a UIViewController) that has 1 UITextField and 3 UIButtons. I use the UIButtons basically as toggles; only 1 can be selected at a time. So each has:
[myButton1 addTarget:self action:#selector(buttonPushed:)
forControlEvents:UIControlEventTouchUpInside];
And I do this to toggle between the buttons:
- (void) buttonPushed:(id)sender
{
myButton1.selected = NO;
myButton2.selected = NO;
myButton3.selected = NO;
if (sender == myButton1) {
myButton1.selected = YES;
}
else if (sender == myButton2) {
myButton2.selected = YES;
}
else if (sender == myButton3) {
myButton3.selected = YES;
}
}
Now the thing is, I still want the buttons to be selectable even if the text field keyboard is up (the buttons and text field are both visible when the keyboard is shown). But since the text field has first responder the button touches are not recognized (never reaches the target buttonPushed method). I don't want the user to have to dismiss the keyboard just to select a button.
How can I do this? Thanks!
I figured it out. The 2 answers here were correct; the problem is that I was using a UITapGestureRecognizer on this view. For some reason that was preventing any touch events from being reached other than the predefined taps I suppose. Doh.
I removed the gesture recognizer and now the touch events are hit when the keyboard is shown.
I've had no problems getting events from buttons with the keyboard up. Are you sure you're not reaching that handler at all?
Any chance myButton1, etc. are not connected?
i think you should use touch methods like
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
or
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
i prefer u to use touchEnded method. here u check if the user taps on uibutton then do what you want
How would I go about adding gesture events to uipickerview to change tabs? I have to create a custom class, however, I don't know how to handle the uipickerview. I current have gestures present in uiviews to do this, but I'm having trouble with the uipickerview.
My code for the views:
#define HORIZ_SWIPE_DRAG_MIN 100
CGPoint mystartTouchPosition;
BOOL isProcessingListMove;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint newTouchPosition = [touch locationInView:self.view];
if(mystartTouchPosition.x != newTouchPosition.x || mystartTouchPosition.y != newTouchPosition.y) {
isProcessingListMove = NO;
}
mystartTouchPosition = [touch locationInView:self.view];
[super touchesBegan:touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint currentTouchPosition = [touch locationInView:self.view];
// If the swipe tracks correctly.
double diffx = mystartTouchPosition.x - currentTouchPosition.x + 0.1; // adding 0.1 to avoid division by zero
double diffy = mystartTouchPosition.y - currentTouchPosition.y + 0.1; // adding 0.1 to avoid division by zero
if(abs(diffx / diffy) > 2.5 && abs(diffx) > HORIZ_SWIPE_DRAG_MIN)
{
// It appears to be a swipe.
if(isProcessingListMove) {
// ignore move, we're currently processing the swipe
return;
}
if (mystartTouchPosition.x < currentTouchPosition.x) {
isProcessingListMove = YES;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:0];
return;
}
else {
isProcessingListMove = YES;
self.tabBarController.selectedViewController = [self.tabBarController.viewControllers objectAtIndex:2];
return;
}
}
else if(abs(diffy / diffx) > 1)
{
isProcessingListMove = YES;
[super touchesMoved:touches withEvent:event];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
isProcessingListMove = NO;
[super touchesEnded:touches withEvent:event];
}
Thanks for the help.
You CAN subclass UIPickerView. The problem is that it's comprised of nine subviews, one of which, called UIPickerTable, is receiving the touch events like touchesBegan:withEvent: to the rows you want. I was able to successfully intercept these with the code included at the end of this post:
Responding to touchesBegan in UIPickerView instead of UIView
The other answers/comments there are helpful too. I wanted to clear the air, not for someone doing something non-standard (as in this question), but for someone who arrived here wishing to subclass UIPickerView, because the first line of the accepted answer is dead wrong.
You can't subclass UIPickerView.
However, since a picker view must be displayed in another view (since it doesn't take up the entire screen) you can trap the touches in that view's controller and filter for gestures.
(Assuming I understand what your trying to do...) I would warn that swiping a picker view to change tabs is a non-standard UI and will probably confuse your users. Since a picker view is perceived as a type of control, they will expect only the normal spinning action of the picker. How would they even know to swipe a picker view horizontally?
I left it alone. It would have been confusing, you're right.
ZT> You can't subclass UIPickerView.
"In order to make the picker view spin longer, I subclassed UIPickerView. My subclass had exactly one method" from Longer Spinning and Blurring. Also see UIPickerView Class Reference: "The UIDatePicker class uses a custom subclass of UIPickerView to display dates and times."
Is it possible to use the touchesMoved function with buttons instead of UIImageViews?
Yes.
In your .h file
IBOutlet UIButton *aButton;
In your .m file
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self.view] anyObject];
CGPoint location = [touch locationInView:touch.view];
if(CGRectContainsPoint(p1.frame, location))
{
if (!p1.isHighlighted){
[self pP01];
[p1 setHighlighted:YES];
}
}else {
[p1 setHighlighted:NO];
}
//
if(CGRectContainsPoint(p2.frame, location))
{
if (!p2.isHighlighted){
[self pP02];
[p2 setHighlighted:YES];
}
}else {
[p2 setHighlighted:NO];
}
if(CGRectContainsPoint(p3.frame, location))
{
if (!p3.isHighlighted){
[self pP03];
[p3 setHighlighted:YES];
}
}else {
[p3 setHighlighted:NO];
}
}
And finally, in Interface Builder, connect your button to 'aButton' and turn off "User Interaction Enabled" for your button.
This is important because it allow touchesMoved to handle it.
I have adjusted the code above to check the buttons highlighted state. This is to stop it from firing the button multiple times when you drag your finger inside the area.
To get your "piano keys" to work when you tap them, use -(void)touchesBegan
To set your button highlight states back to = NO;, use -(void)touchesEnded
I have had to find out the exact same thing you are after. I couldn't figure out Touch Drag Enter
So to avoid multiple posts on the subject, please check out my question and answers.
question 1
question 2
You could certainly find the 'view' that is currently being touch event is dragging over even if it is a button. You could also use the 'touch drag enter' connection for buttons in the Interface Builder. Look at the connections tab by pressing cmd+2 when having selected a button.