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.)
Related
I have the following code in a view controller:
#interface QuizController ()
#property (weak, nonatomic) IBOutlet UITextView *questionText;
#property (weak, nonatomic) IBOutlet UITextView *one;
#property (weak, nonatomic) IBOutlet UITextView *two;
#property (weak, nonatomic) IBOutlet UITextView *three;
#property (weak, nonatomic) IBOutlet UITextView *four;
#property(strong, nonatomic) NSMutableArray* possAnswers;
#end
#implementation QuizController
- (void)viewDidLoad {
[super viewDidLoad];
[self.manager setupGame];
self.possAnswers = [[NSMutableArray alloc] initWithObjects:#"a", #"b", #"c", #"d", nil];
}
//This listens for a tap on any of the TextViews and sets the background to Blue
- (IBAction)fourTapped:(id)sender {
NSLog(#"There's been a tap!");
[self blankBoxes];
if( [sender isKindOfClass:[UITapGestureRecognizer class]] )
{
UITapGestureRecognizer* tgr = (UITapGestureRecognizer*)sender;
UIView* view = tgr.view;
if( [view isKindOfClass:[UITextView class]]){
UITextView* tv = (UITextView*)view;
NSLog([tv text]);
[tv setBackgroundColor:[UIColor blueColor]];
}
}
}
-(void)blankBoxes
{
[_one setBackgroundColor:[UIColor whiteColor]];
[_two setBackgroundColor:[UIColor whiteColor]];
[_three setBackgroundColor:[UIColor whiteColor]];
[_four setBackgroundColor:[UIColor whiteColor]];
}
However, the only UITextView that gets highlighted is _one, no matter which view is tapped. I don't understand why this is. I'd be really grateful if anyone could point this out to me.
Gesture recognizers attach to one and only one view. That's by design. If you want a single gesture recognizer that lets you recognize taps on multiple views, you have to attach it to a common, enclosing superview, then look at the tap coordinates and figure out which view was tapped.
Normally you just create a different gesture recognizer for each view that needs to responds to taps.
Add the UIGestureRecognizer to a UIView that contains your subviews. After that use CGRectContainsPoint() to check if the tap location is in one of the subviews, then continue from there.
CGPoint *touchLocation = [gesture locationInView:self];
for(UIView *view in self.subviews){
if(CGRectContainsPoint(view.frame, touchLocation))
//Your code here
}
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.
How do I customize a UIButton to behave like a table view cell?
I've tried make it in Interface Builder, but since the button is invisible and have no image, it's never gets highlighted when you press it. I want this grayed out behavior like on a table view cell.
Does anyone knows how to do it?
Simple way ever:
Make a 10x10px gray square png image, save it and name it like "greayButtBkg.png" and drag it into SupportingFiles in XCode.
Declare an Outlet of your button into your .h file and an IBAction method into your .m file.
yourFile.h:
#property (weak, nonatomic) IBOutlet UIButton *myButton;
yourFile.m:
- (IBAction)pressButton:(id)sender {
[_myButton setBackgroundImage:[UIImage imageNamed:#"greyButtBkg"] forState:UIControlStateHighlighted];
}
Your Button will get a grey background color when you'll tap it, and go back to its Default clearColor when you'll release your finger.
Hope this helps!
I have created a Custom Control that would behave like UITableViewCell. See code below
MyButton.h
#import <UIKit/UIKit.h>
#interface MyButton : UIView
- (id)initWithFrame:(CGRect)frame selector:(SEL)sel target:(id)target;
#end
MyButton.m
#import "MyButton.h"
#import <QuartzCore/QuartzCore.h>
#interface MyButton()
#property(assign)SEL selector;
#property(assign)id target;
#end
#implementation MyButton
- (id)initWithFrame:(CGRect)frame selector:(SEL)sel target:(id)target
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.selector=sel;
self.target=target;
self.backgroundColor=[UIColor darkGrayColor];
self.layer.cornerRadius=5.0;
UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapAction:)];
[self addGestureRecognizer:tapGesture];
}
return self;
}
-(void)tapAction:(id)sender{
[UIView animateWithDuration:.2 animations:^{
[self setBackgroundColor:[UIColor lightGrayColor]];
}];
[self performSelector:#selector(deSelect) withObject:nil afterDelay:.2];
}
-(void)deSelect{
[UIView animateWithDuration:.2 animations:^{
[self setBackgroundColor:[UIColor darkGrayColor]];
} completion:^(BOOL finished) {
[_target performSelector:_selector withObject:self];
}];
}
/*- (void)drawRect:(CGRect)rect
{
}*/
#end
Since, It uses UIView you can easily add, or draw anything on this control, and easily customize this.
Hope this helps.
Cheers.
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.
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 :-) ).