I'm using a UIPicker to populate a UITextField instead of a keyboard. This works great but I can't close the UIPicker now. I want to be able to tap anywhere on the screen and close the UIPicker. I've tried each of the touches method an none will fire.
setUserInteractionEnabled:YES.
Not sure if it makes a difference but I'm using a StoryBoard
Should I have set something up in my AppDelegate to listen for touches?
Here is my .h
#import <UIKit/UIKit.h>
#interface RNMemberTableViewController : UITableViewController<UIPickerViewDataSource, UIPickerViewDelegate, UITextFieldDelegate>
#property (weak, nonatomic) IBOutlet UIPickerView *behaviorPicker;
#property (nonatomic, weak) IBOutlet UIDatePicker *dateOfRecordPicker;
#property (nonatomic, strong) NSArray *behaviorLevels;
#property (weak, nonatomic) IBOutlet UITextField *behaviorTextField;
#end
here is some of the implementation...
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setUserInteractionEnabled:YES];
[self buildBehaviorPicker];
NSLog(#"Member View");
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"test");
[self.view touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
int tCount = touch.tapCount;
NSLog(#"Touched %d", tCount);
}
- (void) buildBehaviorPicker
{
behaviorLevels = [[NSArray alloc] initWithObjects:#"Unsatisfactory", #"Needs Improvement", #"Satisfactory", #"Outstanding", nil];
UIPickerView *pickerView = [[UIPickerView alloc] init];
pickerView.dataSource = self;
pickerView.delegate = self;
[pickerView selectRow:2 inComponent:0 animated:NO];
self.behaviorTextField.inputView = pickerView;
}
Thanks in advance
-Bob
You can always try the following:
-(void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapReceived:)];
[tapGestureRecognizer setDelegate:self];
[self.view addGestureRecognizer:tapGestureRecognizer];
}
-(void)tapReceived:(UITapGestureRecognizer *)tapGestureRecognizer
{
// do something, like dismiss your view controller, picker, etc., etc.
}
Hope this helps ...
You can add a transparent button of the same size as the controller's view under the picker.
Set button.hidden = NO when the picker is shown and set button.hidden = YES when the picker is hidden.
There are ways to hide the picker. The easiest way is to set picker.hidden = YES.
If you are using UIScrollView then
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
will not be called, as touchesBegan is a method of UIView and not of UIScrollView.
Related
I'm am trying to delete an image while it is moving on the screen using UITapGestureRecognizers and UIViewAnimation. I have used the UIViewAnimationOptionAllowUserInteraction, but I still get the SIGBART error. I have been looking through the internet and couldn't find a solution.
This is my .m file
#import "AbcViewController.h"
#interface AbcViewController ()
#end
#implementation AbcViewController
//single tap gesture action /deletes person
-(void) tapped:(UITapGestureRecognizer *)recognizer{
[recognizer.view removeFromSuperview];
}
//double tap gesture action
-(void) tapped2:(UITapGestureRecognizer *)recognizer{
[recognizer.view removeFromSuperview];
}
- (void)viewDidLoad
{
[super viewDidLoad];
//this makes a zombie/person
UIImageView *zombieView =[[UIImageView alloc] initWithFrame:CGRectMake(135 , 300, 50, 75)];
UIImage *zombie=[UIImage imageNamed:#"free-vector-stick-figure-clip-art_105575_Stick_Figure_clip_art_hight.png"];
[zombieView setImage:zombie];
[self.view addSubview:zombieView];
[self.view insertSubview:zombieView belowSubview:_Railing];
[zombieView setUserInteractionEnabled:TRUE];
// double tap gesture recognizer
UITapGestureRecognizer *touch2 = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped2:)];
[touch2 setDelegate: self];
[touch2 setNumberOfTapsRequired: 2];
[zombieView addGestureRecognizer:touch2];
//tap gesture recognizer
UITapGestureRecognizer *touch = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[touch setDelegate:self];
[touch setNumberOfTapsRequired: 1];
[zombieView addGestureRecognizer:touch];
//This makes the Person move down until he is behind the railing
[UIView animateWithDuration:8.5
delay:0.0
options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveLinear
animations:^{
CGAffineTransform transform= CGAffineTransformMakeTranslation(0,-200);
zombieView.transform = transform;
}
completion:nil];
};
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
This is my .h file:
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface AbcViewController : UIViewController <UIGestureRecognizerDelegate>
#property (strong, nonatomic) IBOutlet UIImageView *Railing;
//#property (strong, nonatomic) IBOutlet UIImageView *Person;
#property (strong, nonatomic) IBOutlet UIImageView *zombieView;
#property (strong, nonatomic) IBOutlet UIImage *zombie;
-(void) tapped:(UITapGestureRecognizer *)recognizer;
-(void) tapped2:(UITapGestureRecognizer *)recognizer;
#end
Every time I click it in mid-animation I get an error but when it's complete it works fine. I am fairly new to this so I'm sure it's simple, it always is. But, thank you for your patience and answers!
The object during the animation is not where you see it. It has already moved to its final position. Animation is an illusion: the "presentation layer" is animated, but the underlying "model layer" (the real object) stands still and has already moved when the animation starts. The model layer is the one inside a view so it is the only one that can be tapped.
Tapping an object while it is being animated is therefore a very tricky problem. I discuss it here:
http://www.apeth.com/iOSBook/ch18.html#_hit_testing_during_animation
Perhaps that discussion will give you some ideas. But no matter what, this is not going to be easy.
(Consider that perhaps you should not be using view animation for this kind of game. Sprite Kit was invented for just this sort of thing.)
I have been trying to do this simple thing : adding an action to a simple custom view. I have looked over the internet and found two "easy" solution :
UITapGestureRecognizer
UIButton
I want to do this programmatically and I just need to handle the tap.
Here is my code so far, I've tried both solutions separately and together and it doesn't work !
.m
#import "AreaView.h"
#implementation AreaView
#define GREY 27.0/255.0
#define PINK_R 252.0/255.0
#define PINK_G 47.0/255.0
#define PINK_B 99.0/255.0
- (id) initWithFrame:(CGRect)frame imageName:(NSString *)imageName areaName:(NSString *)areaName minimumSpending:(int)minimumSpending andCapacity:(int)capacity
{
self = [self initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor colorWithRed:GREY green:GREY blue:GREY alpha:1];
self.userInteractionEnabled=YES;
//Init variables
_areaName=areaName;
_capacity=capacity;
_minimumSpending=minimumSpending;
//Image view
_logoImageView = [[UIImageView alloc]initWithFrame:CGRectMake(5, 4, 66, 50)];
//_logoImageView.image = [UIImage imageNamed:imageName];
_logoImageView.backgroundColor = [UIColor grayColor];
//Label
_areaNameLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 54, 76, 18)];
_areaNameLabel.textAlignment = NSTextAlignmentCenter;
_areaNameLabel.textColor = [UIColor whiteColor];
_areaNameLabel.font = [UIFont systemFontOfSize:12.0];
_areaNameLabel.text = areaName;
//button
_button = [[UIButton alloc]initWithFrame:self.bounds];
_button.userInteractionEnabled=YES;
_button.backgroundColor=[UIColor yellowColor];
[_button addTarget:self action:#selector(handleTap:) forControlEvents:UIControlEventTouchUpInside];
//tap gesture racognizer
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapped:)];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setDelegate:self];
[self addGestureRecognizer:tapRecognizer];
[self addSubview:_logoImageView];
[self addSubview:_areaNameLabel];
[self addSubview:_button];
}
return self;
}
-(void)handleTap:(UIButton *)button
{
NSLog(#"tapped!");
}
-(void)tapped:(UITapGestureRecognizer *)recognizer
{
NSLog(#"tapped!");
}
#end
.h
#import <UIKit/UIKit.h>
#interface AreaView : UIView <UIGestureRecognizerDelegate>
#property (nonatomic) UIImageView *logoImageView;
#property (nonatomic) UILabel *areaNameLabel;
#property (nonatomic) NSString *areaName;
#property (nonatomic) int minimumSpending;
#property (nonatomic) int capacity;
- (id) initWithFrame:(CGRect)frame imageName:(NSString *)imageName areaName:(NSString *)areaName minimumSpending:(int)minimumSpending andCapacity:(int)capacity;
#property (nonatomic, strong) UIButton *button;
#end
Thanks for your help!
EDIT
The problem is that both handleTap and tapped are never fired even if I comment the button solution or the tap gesture one to test them separately. For the button implementation, I can see it on my interface but clicking on it does nothing.
My UIView is then added programmatically several times (for several views) in a UIScrollview.
EDIT 2
The problem is more complicate than that. The custom view is inside a scrollview which is inside another different custom view whose main function is to rewrite hittest, so that touches on this view are held by the scrollview. (Here is the purpose of all that).
It seems that as long as hittest is involved, it doesn't work.
Implement this delegate method, which will help you.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
id touchedView = gestureRecognizer.view;
if ([touchedView isKindOfClass:[UIButton class]])
{
return NO; //It won't invoke gesture method, But it'll fire button method.
}
return YES;
}
I'm not sure why your UIButton and UITapGestureRecognizer selectors aren't firing. However another option to handle taps on a view is to simply override the touchesEnded:withEvent method:
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
//handle a tap
}
That way, you won't have to create a UIButton or a UITapGestureRecognizer object at all.
This has been asked a few times, but I don't seem to get it.
I have a view controller, with two textfields, one segmented control, a date picker and a few labels.
I want to dismiss the keyboard, when the user clicks the background or the segmented control or the date picker.
Here is my .h file:
#interface MRPatientenViewController : UIViewController
#property (nonatomic, strong) MRPatientenTableViewController *delegate;
- (IBAction)textFieldReturn:(id)sender;
#property (strong, nonatomic) IBOutlet UITextField *nachnameTextField;
#property (strong, nonatomic) IBOutlet UITextField *vornameTextField;
#property (strong, nonatomic) IBOutlet UIDatePicker *geburtsdatumPicker;
#property (strong, nonatomic) IBOutlet UISegmentedControl *genderSegmentedControl;
#end
this is my .m file:
-(IBAction)textFieldReturn:(id)sender{
[sender resignFirstResponder];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
if ([_nachnameTextField isFirstResponder] && [touch view] != _nachnameTextField) {
[_nachnameTextField resignFirstResponder];
}
else if ([_vornameTextField isFirstResponder] && [touch view] != _vornameTextField) {
[_vornameTextField resignFirstResponder];
}
[super touchesBegan:touches withEvent:event];
}
Now this dismisses the keyboard, if the background or the labels are touched.
But how do I dismiss the keyboard if the UISegmentedControl or the datepicker is touched?
You Touch code is correct but it also working fine in my code.when you click outside of text-field at that time Touch event call but its inner condition is not working good.i remove the condition and check its working fine.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[nachnameTextField resignFirstResponder];
[super touchesBegan:touches withEvent:event];
}
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
[geburtsdatumPicker addGestureRecognizer:tap];
[genderSegmentedControl addGestureRecognizer:tap];
[self.view addGestureRecognizer:tap];
Then resign keyboard inside the selector
-(void) dismissKeyboard
{
[nachnameTextField resignFirstResponder];
[vornameTextField resignFirstResponder];
}
Have you tried following line of code
[textfieldInFocus resignFirstResponder];
You can do the following:
UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(tapAction)];
tapGesture.delegate=self;
[self.view addGestureRecognizer:tapGesture];
- (void)tapAction
{
[nachnameTextField resignFirstResponder];
[vornameTextField resignFirstResponder];
}
and for UISegmentedControl or UIDatePicker you probably have their own selector methods for example:
For UISegmentedControl :
- (IBAction)mainSegmentControl:(UISegmentedControl *)segment{
}
or For UIDatePicker :
- (void)changeDate:(UIDatePicker *)sender {
}
just call your method [self tapAction]; in both above methods and you are good to go...!!
This is the solution which worked for me: the MRViewController.h file:
#import <UIKit/UIKit.h>
#interface MRViewController : UIViewController <UITextFieldDelegate>
#property (strong, nonatomic) IBOutlet UITextField *textField;
#property (strong, nonatomic) IBOutlet UISegmentedControl *segmentedControl;
#end
The MRViewController.m file:
- (void)viewDidLoad
{
[super viewDidLoad];
[self hideKeyboardWhenBackgroundIsTapped];
self.textField.delegate = self;
}
-(void)hideKeyboardWhenBackgroundIsTapped{
UITapGestureRecognizer *tgr = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(hideKeyboard)];
[tgr setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:tgr];
}
-(void)hideKeyboard{
[self.view endEditing:YES];
}
And in my storyboard scene, I got a UITextField and a UISegmentedControl.
The keyboard hides when I click search or when I click on cancel.
But I want also that the keyboard hides when I click somewhere on the screen.
I found several tutorials for the textfield, but we are using the search bar.
Can someone tell me how to do this?
Thanks.
Try This
in your .h file add UISearchBar
#property (strong, nonatomic) IBOutlet UISearchBar *searchBar;
in your .m file
- (void)viewDidLoad
{
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
- (void) dismissKeyboard
{
// add self
[self.searchBar resignFirstResponder];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[yourTextField1 resignFirstResponder];
[yourTextField2 resignFirstResponder];
[yourTextField3 resignFirstResponder];
[yourSearchBar resignFirstResponder];
//etc
}
But probably you need to check where are you touching at since you don't want to hide the keyboard if you're touching on a text input or search box.
Try to use this one
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.view endEditing:YES];
}
You could add a UITapGestureRecognizer to dismiss your keyboard.
- (void)viewDidLoad {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
- (void) dismissKeyboard {
[self.view endEditing:YES];
}
So I read quite a bit, but still I can't find the solution.
I have a UIViewController which is creating (programatically) a UIScrollView, which Contains a UIView and a UIImage. The UIView lies on top of the rest.
This UIView generates some UIImageViews which I need to get feedback from when tapped. I need to know which image was tapped by getting their tags. That's why I can't use gesture recognizer, since it can only be called on one view.
If I call this:
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
NSLog(#"tag=%#", [NSString stringWithFormat:#"%i", touch.view.tag]);
}
On the view (called GraphView, which has it's own class) I get what I need. Still, I need to do this from the ViewController side because I have to open modal window, navigation controllers, etc... If I use that same code on the ViewController nothing happens. If I disable User Interaction on the UIScrollView it works. If I disable the delay on the UIScrollView nothing happens. No matter how long you press you get nothing. touchesBegan doesn't get called at all even if the delay is enabled.
Here's the part of the implementation of the ViewController where I generate the Views:
// ScrollView
CGRect frame = CGRectMake(0, 0, 480, 320);
myScrollView = [[UIScrollView alloc] initWithFrame:frame];
myScrollView.backgroundColor = [UIColor blackColor];
myScrollView.showsVerticalScrollIndicator = YES;
myScrollView.showsHorizontalScrollIndicator = YES;
myScrollView.userInteractionEnabled = YES;
myScrollView.contentSize = CGSizeMake(SCROLLVIEW_WIDTH, SCROLLVIEW_HEIGHT);
myScrollView.delegate = self;
[self.view addSubview:myScrollView];
// Add UIImage for background
UIImageView *backgroundGraph = [[UIImageView alloc] initWithFrame:CGRectMake (0,0,SCROLLVIEW_WIDTH,SCROLLVIEW_HEIGHT)];
backgroundGraph.image = [UIImage imageNamed:#"graph_background.png"];
backgroundGraph.userInteractionEnabled = YES;
[myScrollView addSubview:backgroundGraph];
//[self.view addSubview:backgroundGraph];
[backgroundGraph release];
// Add View for Graph.
GraphView *graphViewC = [[GraphView alloc] init];
self.graphView = graphViewC;
graphView.tag = 200;
graphView.userInteractionEnabled = YES;
graphView.frame = CGRectMake(0, 0, SCROLLVIEW_WIDTH, SCROLLVIEW_HEIGHT);
graphView.backgroundColor = [UIColor clearColor];
[myScrollView addSubview:graphView];
//[self.view addSubview:graphView];
.h file on ViewController looks like this:
#import <UIKit/UIKit.h>
#class GraphView;
#interface TrackingViewController : UIViewController <UIScrollViewDelegate> {
UIScrollView *myScrollView;
GraphView *graphView;
int someNum;
#define SCROLLVIEW_HEIGHT 273
#define SCROLLVIEW_WIDTH 599
}
#property (nonatomic, retain) GraphView *graphView;
- (void) openModal;
//- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer;
#property (nonatomic, retain) UIScrollView *myScrollView;
#end
As always, I am thankful to everyone who can help with any ideas(and I've gotten a lot of help here always, so thanks in advance :-) ).