I have a UICollectionView to which I have added UILongPressGestureRecognizer and UIPangestureRecognizer for long press and reordering cells. And also I have added UIPanGestureRecognizer for all the UICollectionViewCells to show delete and few options on the right side.
My problem is when I pan two UICollectionViewCells with two fingers, both the UICollectionViewCells are detecting the pan and showing the options.
I want only one of the UICollectionViewCell to detect its UIPangestureRecognizer at a time. Is there any solution?.
Can anyone please help me out on this?.
Thanks in advance.
Have you tried the minimumNumberOfTouches / maximumNumberOfTouches property of UIPangestureRecognizer?
You can disable multi touch on collection it self. by making simple property.
[UICollectionView setMultipleTouchEnabled:NO];
If still problem is not being solve due to Gesture view implementation then you can use TouchedFlag for maintain touch on cell.
You can set in
- (IBAction) panGesture:(UIPanGestureRecognizer *)gesture;
You can set TouchedFlag to 1 while
if (gesture.state == UIGestureRecognizerStateBegan)
{
TouchedFlag=1;
}
And set back while PanGesture get ended in
if (gesture.state == UIGestureRecognizerStateEnded)
{
TouchedFlag=0;
}
So your finale code should look like
- (IBAction) panGesture:(UIPanGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan && TouchedFlag==0)
{
TouchedFlag=1;
//Do your PAN openration
}
else if (gesture.state == UIGestureRecognizerStateBegan && TouchedFlag==1) {
//just prompt msg to user then single view at a time allowd to PAN
}
else if (gesture.state == UIGestureRecognizerStateEnded) {
TouchedFlag=0;
}
}
Related
I want to change background color of UIView tap, I know how to catch touch events and gestures on UIView in iOS.
I can change color when touchesBegan fires and then change it to original color when touchesEnded or touchesCancelled fires.
This works fine, until user tap on UIView really fast, this can be determined by UITapGestureRecognizer and change background color, but I don't know how to change color after that!
I don't want to use some kind of "Timer" or similar approach.
any suggestion?
You can detect that the tap ended by checking its state:
Objective-C
if (recognizer.state == UIGestureRecognizerStateEnded) {
// change the color here
}
Swift
if recognizer.state == .Ended {
// change the color here
}
From your question it seems that you have successfully done it with following delegates of UIView.
touchesBegan:
touchesEnded:
touchesCancelled:
The second option is to use UITapGestureRecognizer which was already mentioned by you. Please try using following code in your gesture recognizer method.
Add gesture to your view:
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(viewTap:)];
[yourView addGestureRecognizer:tapGesture ];
Your gesture recognizer method
-(void) viewTap:(UITapGestureRecognizer *) gestureRecognizer
{
if(gestureRecognizer.state == UIGestureRecognizerStateEnded)
{
//All fingers are lifted.
}
}
I have a UIScrollView instance with a subview that has its own UIPanGestureRecognizer which is used to move the subview inside the scrollview. I would like the pinch-to-zoom feature of the scrollview to have the top priority over the pan gesture. However, this is not the case: when starting to pinch with one finger over my subview, it will pan instead.
What I tried so far:
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:: it will pan AND pinch
[panGestureRecognizer requireGestureRecognizerToFail:scrollView.pinchGestureRecognizer];: panning just won't work anymore (callback is triggered only for UIGestureRecognizerStateEnded state). And panGestureRecognizer.cancelsTouchesInView = NO won't help.
My understanding is that when starting to pinch from the subview, both the scroll view and the subview only receive one touch each, that's why in the second case the pinch gesture recognizer doesn't even fail because it doesn't even begin to handle the event.
So, any idea on how to achieve this?
One way to do it is to allow simultaneous interaction with the scrollView.pinchGestureRecognizer, and then cancel the panGestureRecognizer if the scrollView.pinchGestureRecognizer is actually zooming. The only way I know how to cancel them is to disable/enable.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if (gestureRecognizer == panGestureRecognizer){
if (otherGestureRecognizer == scrollView.panGestureRecognizer) {
return 0;
}
else if(otherGestureRecognizer == scrollView.pinchGestureRecognizer){
if (scrollView.pinchGestureRecognizer.scale != 1) {
gestureRecognizer.enabled = 0;
gestureRecognizer.enabled = 1;
}
}
}
return 1;
}
I have a UILongPressGestureREcognizer with a minimum press length of 0 seconds. On UIGestureRecognizerStateStart I alter the UIView. On UIGestureRecognizerStateEnded, I run the code for what ever the press is suppose to do.
-(IBAction)longPressDetected:(UILongPressGestureRecognizer *)recognizer {
static NSTimer *timer = nil;
if (recognizer.state == UIGestureRecognizerStateBegan) {
// alter look of UIView
}
else if (recognizer.state == UIGestureRecognizerStateEnded) {
// do something
// change look back to original state
}
}
I am running into an issue where if the touch starts on the UIView and if the touch is dragged outside of the UIView and is lifted, the UIGestureRecognizerStateEnded still fires.
I need to be able to handle a touch inside the UIView, the user drag outside of the UIView and to cancel it.
I know a UIButton can do it, but it does not fulfill all the needs I have.
How can I cancel a touch if the touch is dragged outside of the UIView?
Add checking of touch location. This method can be heplfull.
- (CGPoint)locationInView:(UIView *)view
I have UIView and I attached to it a UIPanGestureRecognizer.
inside the UIView I have UIScrollView with paging enabled and I set the content size so scrollView could be scrolled just to the left.
the problem:
I want when user try to drag scrollView To the right, to send the event up to UIView so 'UIPanGestureRecognizer' can handle the touch event
at last, after 6 hours I figure it out
I subclassed UIScrollView and implemented gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer delegate method
when user drag over the scrollView this method get called (BOOL)gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer and by default it returns NO
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
if (self.contentOffset.x > 0 && self.contentOffset.x <= self.contentSize.width - self.frame.size.width) {
//user is in middle of dragging the scrollView don't allow any other gestureRecognizer to respond
return NO;
}else{
//scrollView contentOffset is 0 and user is not dragging the scrollView so let other gestureRecognizer to respond
return YES;
}
}
In trying to use homam's answer, I realized that the scrollView.panGestureRecognizer was being cut off after a return NO. What I wanted was for my custom pan recognizer to be cut off and the scrollView to still scroll. I think that might've been the result of the gestures being added at different levels, I'm not sure.
I found a solution, however, by changing my custom gesture recognizer to check for the scrollView.contentOffset and not activate unless it was greater than zero. I also turned off the scrollView.bounce property once the scrollView.contentOffset got to zero. When scrolling down on my scrollView it would hit the end and immediately my gesture recognizer would take over and move the superview out of the way like I wanted.
Here's a skeleton of my custom pan gesture
- (void)customPan:(UIPanGestureRecognizer*)panRecognizer
{
if(panRecognizer.state == UIGestureRecognizerStateBegan)
{
//do begin stuff
}
if(panRecognizer.state == UIGestureRecognizerStateChanged)
{
if(self.scrollView.contentOffset.y > 0)
{
//do begin stuff to make sure it’s initialized properly when it does start to change
self.scrollView.bounces = YES;
return;
}
else
{
self.scrollView.bounces = NO;
}
//do change stuff
}
if(panRecognizer.state == UIGestureRecognizerStateEnded)
{
if(self.scrollView.contentOffset.y > 0)
{
//do begin stuff to make sure it’s initialized properly when it does start to change
self.scrollView.bounces = YES;
return;
}
else
{
self.scrollView.bounces = NO;
}
//do end stuff
}
}
[myScrollView setContentSize:CGSizeZero];
I'm trying to implement a UIView that can be dragged out of its superview.
I tried adding a UIPanGestureRecognizer to the view I want to be able to drag. It seems, however, that removing the UIView from its superview and adding it to another view, is breaking the gesture recognizer.
With the code within the UIGestureRecognizerStateBegan commented out, the code within the other two blocks functions correctly, but when I reinstate it, the UIGestureRecognizerStateChanged and UIGestureRecognizerStateEnded states are never achieved.
What is going wrong?
if ([gr state] == UIGestureRecognizerStateBegan)
{
CGPoint newCenter = [endView convertPoint:[self center]
fromView:startView];
[self removeFromSuperview];
[endView addSubview:self];
[self setCenter:newCenter];
}
if ([gr state] == UIGestureRecognizerStateChanged)
{
// Some code that successfully moves the view.
}
if ([gr state] == UIGestureRecognizerStateEnded)
{
// Other code.
}
You deduce right, [self removeFromSuperview] breaks gesture recognizer. I have had the same problem. Comment this line [self removeFromSuperview] and should be ok, you don't have to remove it from superview, because UIView can only be a subview of one view.