I would like to give a UIButton different features depending on if it is pressed and released once, or held down (ideally for 1.5 sec) and moved around the screen. I am using this code at the moment:
[button addTarget:self action:#selector(open:)
forControlEvents:UIControlEventTouchDown]
panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(move:)];
[panRecognizer setMinimumNumberOfTouches:1];
[panRecognizer setMaximumNumberOfTouches:1];
[panRecognizer setDelegate:self];
[button addGestureRecognizer:panRecognizer];
-(IBAction)open:(id)sender {}
-(void)move:(id)sender{}
move: works fine, but open: doesn't.
maybe you can use button's drag event, like
[button addTarget:self action:#selector(wasDragged:withEvent:)
forControlEvents:UIControlEventTouchDragInside];
You can look at this link: http://www.cocoanetics.com/2010/11/draggable-buttons-labels/
you can put a flag in move mehod, when enter touch up method, you check if the button has moved, to decide to trigger open related logic
#define BUTTON_DRAGGED_TAG -100
#define BUTTON_DEFAULT_TAG 0
- (void)onButtonTouchUpInside:(UIButton *)button withEvent:(UIEvent *)event
{
if (button.tag != BUTTON_DRAGGED_TAG)
{
//doOpen
}
button.tag = BUTTON_DEFAULT_TAG;
}
- (void)onButtonTouchUpOutside:(UIButton *)button withEvent:(UIEvent *)event
{
button.tag = BUTTON_DEFAULT_TAG;
}
- (void)onButtonTouchCancel:(UIButton *)button withEvent:(UIEvent *)event
{
button.tag = BUTTON_DEFAULT_TAG;
}
- (void)onButtonDraged:(UIButton *)button withEvent:(UIEvent *)event
{
button.tag = BUTTON_DRAGGED_TAG;
}
I did this, let me know if it works for you:
- (void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didRecognizeTapGesture:)];
tapGesture.cancelsTouchesInView = NO;
tapGesture.delegate = self;
[tapGesture requireGestureRecognizerToFail:self.scrollView.panGestureRecognizer];
[self.scrollView addGestureRecognizer:tapGesture];
self.tapGesture = tapGesture;
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view == self.button)
{
return NO;
}
return YES;
}
- (void)didRecognizeTapGesture:(UITapGestureRecognizer*)gesture
{
if (gesture.state == UIGestureRecognizerStateEnded)
{
NSLog(#"GESTURE ENDED");
}
}
- (void)didPressButton:(UIButton*)sender
{
NSLog(#"BUTTON TOUCH UP INSIDE");
}
Related
I want to add multiple UITapGestureRecognizer on UIScrollView but it recognise only one gesture.
I want to add first gesture for touch begin and second one for touch end event.
Following is my code:-
self.tapStartGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
self.tapStartGesture.numberOfTapsRequired = 1;
self.tapStartGesture.numberOfTouchesRequired = 1;
[self.tapStartGesture setState:UIGestureRecognizerStateBegan];
[self.scrollView addGestureRecognizer:self.tapStartGesture];
self.tapEndGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGesture:)];
self.tapEndGesture.numberOfTapsRequired = 1;
self.tapEndGesture.numberOfTouchesRequired = 1;
[self.scrollView addGestureRecognizer:self.tapEndGesture];
- (void)tapGesture:(UITapGestureRecognizer *)sender {
if(sender==self.tapStartGesture) {
NSLog(#"tapStartGesture");
} else if(sender==self.tapEndGesture) {
NSLog(#"tapEndGesture");
}
}
A tap gesture only has one state - "ended". You can't detect when a tap starts using a tap gesture. As you've seen, attempting to use two tap gestures doesn't accomplish what you want.
You need to implement the UIResponder methods touchesBegan and touchesEnded.
You may also want to see UITapGestureRecognizer - make it work on touch down, not touch up?
.
Issue solved by implement custom gesture.
File:-MyGesture.h
#import <UIKit/UIKit.h>
#interface MyGesture : UIGestureRecognizer
#end
File:-MyGesture.m
#import "MyGesture.h"
#implementation MyGesture
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
if (self.state == UIGestureRecognizerStatePossible) {;
self.state = UIGestureRecognizerStateBegan;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
self.state = UIGestureRecognizerStateEnded;
}
#end
How to Use:-
MyGesture *gesture = [[MyGesture alloc] initWithTarget:self action:#selector(myGesture:)];
[self.scrollView addGestureRecognizer:gesture];
- (void)myGesture:(MyGesture *)sender {
if (sender.state == UIGestureRecognizerStateBegan) {
NSLog(#"tapStartGesture");
} else if (sender.state == UIGestureRecognizerStateEnded) {
NSLog(#"tapEndGesture");
}
}
I have some textfield in which when i click it shows me keyboard , but when i click anywhere on the page the keyboard do not disappears . This is my code for resign of first responder. Whats wrong in my code.
Add this code:
-(void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapReceived:)];
[tapGestureRecognizer setDelegate:self];
[self.view addGestureRecognizer:tapGestureRecognizer];
}
-(void)tapReceived:(UITapGestureRecognizer *)tapGestureRecognizer
{
[textField resignFirstResponder];
}
Create iVar for UIGestureRecognizer
UIGestureRecognizer *tapper;
- (void)viewDidLoad
{
[super viewDidLoad];
tapper = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleSingleTap:)];
tapper.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:tapper];
}
Dismiss what ever is currently editing:
- (void)handleSingleTap:(UITapGestureRecognizer *) sender
{
[self.view endEditing:YES];
}
Try this code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
if(touch.phase == UITouchPhaseBegan) {
[aTextField resignFirstResponder];
}
}
Or
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch * touch = [touches anyObject];
if(touch.phase == UITouchPhaseBegan) {
[self.view endEditing:YES];
}
}
- (void)viewDidLoad {
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard)];
[self.view addGestureRecognizer:tap];
}
-(void)dismissKeyboard {
[yourtextfield resignFirstResponder];
}
Add Tap Gesture on your Top View
you you havn't any subview which may hide your Root view
than only use self.view
if you are using ScrollView than add TapGesture on your ScrollView
-(void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapDissmiss:)];
[self.view addGestureRecognizer: tap];
}
Handle Tap Gesture
-(void)tapDissmiss:(UITapGestureRecognizer *)tapGestureRecognizer
{
[self.view endEditing:YES];
}
Create one UITapGestureRecognizer as a class variable.
#interface ViewController() {
UITapGestureRecognizer *tapGesture;
}
- (void)viewDidLoad {
[super viewDidLoad]
tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(dismissKeyboard)];
}
Add gesture on textfield delegates textFieldDidBeginEditing, And remove it on textFieldDidEndEditing.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[self.view addGestureRecognizer:_tapGesture];
}
- (void)textFieldDidEndEditing:(UITextField *)textField {
[self.view removeGestureRecognizer:_tapGesture];
}
Implement tap gesture selection
- (void)dismissKeyboard {
[self.view endEditing:YES];
}
Following is the code I have written to put 2 finger swipe on UITableView :
UISwipeGestureRecognizer *leftSwipe = [UISwipeGestureRecognizer new];
[leftSwipe addTarget:self action:#selector(nextDay)];
leftSwipe.numberOfTouchesRequired = 2;
leftSwipe.direction = UISwipeGestureRecognizerDirectionLeft;
leftSwipe.delegate = self;
[leftSwipe setCancelsTouchesInView:YES];
[tableViewTasks addGestureRecognizer:leftSwipe];
UISwipeGestureRecognizer *rightSwipe = [UISwipeGestureRecognizer new];
[rightSwipe addTarget:self action:#selector(previousDay)];
rightSwipe.numberOfTouchesRequired = 2;
rightSwipe.direction = UISwipeGestureRecognizerDirectionRight;
rightSwipe.delegate = self;
[rightSwipe setCancelsTouchesInView:YES];
[tableViewTasks addGestureRecognizer:rightSwipe];
I am using SWTableViewCell which has left and right (single tap) gestureRecognisers.
When UITableView is swiped left/right using 2 fingers, SWTableViewCell left and right gestures are also fired after that.
How to stop the conflict ?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if (SWTableViewCellTouch) {
SWTableViewCellTouch = NO
return NO;
}
return YES;
}
when you touch the SWTableViewCell set a BOOL SWTableViewCellTouch to YES.
The possible solution is enable/disable the BOOl (SWTableViewCellTouch) in the touchesBegan: method as below.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([[event touchesForView:self] count] > 1) {
// Its two finger touch so set the BOOL false like
SWTableViewCellTouch = NO;
}
else if ([[event touchesForView:self] count] == 1){
// Its sigle finger touch so set the BOOL true like
SWTableViewCellTouch = YES;
}
[super touchesBegan:touches withEvent:event] ;}
Hope this will help you.
1. Implement UIGestureRecognizerDelegate in your UIViewController
2. Set leftSwipe.delegate = self; and leftSwipe.delegate = self;
3. Now check if the in its Delegate Method if UISwipeGesture have how many numberOfTouchesRequired
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ( [gestureRecognizer isMemberOfClass:[UISwipeGestureRecognizer class]] ) {
UISwipeGestureRecognizer *swipeGesture=(UISwipeGestureRecognizer *)gestureRecognizer ;
if(swipeGesture.numberOfTouchesRequired!=2)
{
//if Double not Double Swipe Touch Don't Linsten Gesture in your Viewcontroller
return NO;
}
}
return YES;
}
i hope this will solve your problem
I believe I have an issue with UITapGestureRecognizer for dismissing keyboard when tapping in chatroom area preventing or blocking touch to the previewCancelButton. Here below are my relevant codes:
BaseTemplateVC.m
- (void)addDismissKeyboardGesture {
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(dismissKeyboard:)];
tapGesture.cancelsTouchesInView = NO;
tapGesture.delegate = self;
self.view.tag = 111;
[self.view addGestureRecognizer:tapGesture];
}
- (void) dismissKeyboard:(id)sender {
UITapGestureRecognizer *gesture = sender;
UIView *view = gesture.view;
NSLog(#"%ld", (long)view.tag);
[self.view endEditing:YES];
}
ChatroomVC.m
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//Disallow recognition of tap gestures in the segmented control.
if (([touch.view isKindOfClass:[UIButton class]])) {
NSLog(#"noooooooo");
return NO;
}
return YES;
NSLog(#"yesssssss");
}
InputFunctionView.m
- (void)selectedSticker:(NSString *)stickerURLString {
/* Sticker preview subview */
stickerPreviewView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -120, FrameWidth, 120)];
stickerPreviewView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5f];
stickerPreviewView.userInteractionEnabled = YES;
[self addSubview:stickerPreviewView];
[self bringSubviewToFront:stickerPreviewView];
/* Initialise previewCancelButton */
self.previewCancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.previewCancelButton.frame = CGRectMake(Main_Screen_Width-30, SpaceForItems-120, 20, 20);
[self.previewCancelButton setBackgroundImage:[UIImage imageNamed:#"btn_previewcancel.png"] forState:UIControlStateNormal];
[self.previewCancelButton setBackgroundImage:[UIImage imageNamed:#"btn_previewcancel.png"] forState:UIControlStateHighlighted];
[self.previewCancelButton addTarget:self action:#selector(cancelStickerPreviewButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview: self.previewCancelButton];
}
/* Cancel sticker preview subview */
- (void)cancelStickerPreviewButtonPressed:(id)sender {
NSLog(#"cancel sticker preview");
[self.previewCancelButton removeFromSuperview];
[stickerPreviewView removeFromSuperview];
}
Now the previewCancelButton is correctly on right top corner of stickerPreviewView but unable to receive touch event to it. When I touch the button it shows "111" in the console and when I traced back I found BaseTemplateVC.m that contains addDismissKeyboardGesture method, so I believe this may cause the issue.
Anyone can guide me to some solutions. That'd be really appreciated. Thanks in advance.
Progress: I have modified gestureRecognizer method in ChatroomVC.m so now it can ignore tap gesture on the button but the problem remains action for the button doesn't get fired.
Just take a try with this, i guess it will work.
Use the shouldReceiveTouch delegate method of gesture, and return NO when the touch.view is button class.
So when it finds button It will discard the gesture and take button action.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// Block the recognition of tap gestures in the button.
if (([touch.view isKindOfClass:[UIButton class]])) {
return NO;
}
return YES;
}
Here is the demo implementation :
I have taken the button on main view of view controller in the story board.
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapGestureClicked:)];
tapGesture.delegate = self;
[self.view addGestureRecognizer:tapGesture];
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// Disallow recognition of tap gestures in the segmented control.
if (([touch.view isKindOfClass:[UIButton class]])) {
return NO;
}
return YES;
}
- (IBAction)btnTestClicked:(UIButton *)sender {
NSLog(#"test button click");
}
- (void)tapGestureClicked:(UIGestureRecognizer *)recog
{
NSLog(#"tap gesture clicked");
}
Hope it helps.
Happy coding ...
I found a solution to this by using below code in GestureRecogniser delegate method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isDescendantOfView:IFView.stickerPreviewView]) {
return NO;
}
return YES;
}
It specifies exactly what subview in this case IFView.stickerPreviewView is to return NO. Also in InputFunctionView, use this instead to add the subview:
[self.superview addSubview:_stickerPreviewView];
From my side I will try bellow code, but it is not working.
- (void) handleTouch:(UITapGestureRecognizer *) gesture
{
CGPoint touchPoint = [gesture locationInView:self.view];
NSArray *viewsAtPoint = [self viewsAtPoint:touchPoint];
for(TheifView * aView in viewsAtPoint)
{
[aView removeFromSuperview];
}
}
- (void) registerGesture
{
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleTouch:)];
tapGesture.numberOfTapsRequired = 1;
[self.view addGestureRecognizer:tapGesture];
}
Gesture target and selector can be removed by following code
[gesture removeTarget:self action:#selector(handleTouch:)];
Put tag to ThiefView...say 111. and then u can identify it and remove from self.view. If this is not the answer you expected then explain with clear description..
//For Removing Gestures from View..
for (UIGestureRecognizer *recognizer in self.view.gestureRecognizers) {
if ([recognizer isKindOfClass:[UITapGestureRecognizer class]]) {
[self.view removeGestureRecognizer:recognizer];
}
}
//For Removing ThiefView from View
for (UIView *subview in self.view.subviews) {
if (subview.tag==111) {
[subview removeFromSuperview];
}
}
To remove it fully
- (void) handleTouch:(UITapGestureRecognizer *) gesture
{
[self.view removeGestureRecognizer:gesture];
}
To remove its target
- (void) handleTouch:(UITapGestureRecognizer *) gesture
{
[gesture removeTarget:self action:#selector(handleTouch:)];
}
To disable the gesture
- (void) handleTouch:(UITapGestureRecognizer *) gesture
{
gesture.enabled=NO;
}