Changing superview breaks UIPanGestureRecognizer - ios

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.

Related

How to disable multi touch on UIPangestureRecognizer?

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;
}
}

How to detect the touch point of iCarouselButtonDemo?

I am using iCarouselButtonDemo to create an arc button menu. I want to disable the scrolling when user touch the space other than the buttons. But now we can scroll the view by touching every point of the UIView. How can I detect the touch point of the view and disable the scrolling when user touch the outside of the 5 buttons
This is my view. This is scrolling when I touch even the bottom of the view. How can I stop it?
Thanks
In the iCarousel implementation file, you will add the following code in gestureRecognizerShouldBegin method. So it looks like this. It firstly get the touch point in the iCarousel view, and find the inner most view responding to the touch through hitTest. If the view is not a button, you stop the pan gesture.
if ([gesture isKindOfClass:[UIPanGestureRecognizer class]])
{
CGPoint point = [gesture locationInView:self];
UIView *touchedView = [self hitTest:point withEvent:nil];
if (![touchedView isKindOfClass:[UIButton class]]) {
return NO;
}
//ignore vertical swipes

UIGestureRecognizer with a touch moving off UIView

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

Horizontal scroll on UIScrollView without pan gesture

How can I make it so that when I use my UIScrollView the pan gesture recognizer selector is not called.
I want to be able to scroll in the scroll view without the pan gesture selector being called.
Here is my pan detected function:
- (void)panDetected:(UIPanGestureRecognizer *)panRecognizer
{
CGPoint translation = [panRecognizer translationInView:self.view];
CGPoint imageViewPosition = self.draggableImage.center;
imageViewPosition.x += translation.x;
imageViewPosition.y += translation.y;
self.draggableImage.center = imageViewPosition;
[panRecognizer setTranslation:CGPointZero inView:self.view];
}
I do not want it to be called when I am using my UIScrollView at the bottom of the page.
you could remove the gesture recognizer from the scroll view
NSArray* gestureRecognizers = [scrollView gestureRecognizers];
for (UIGestureReconizer* recog in gestureRecognizers) {
if ( [recog isKindOfClass:[UIPanGestureRecognizer Class]] )
[recog removeTarget:scrollView.delegate action:#selector(scrollViewDidScroll:)];
}
I don't understand why this is needed to be done, but here it is.
Not exactly sure what you're trying to accomplish here. I haven't played with this, but my initial thought is that if you disable the pan recognizer, your scroll view isn't gonna scroll. Your scrollview calculates where and how to scroll based on the what the pan recognizer is telling it.
If you have an alternative setup to handle the scrolling, then by all means:
UIScrollView *scrollView;
[[scrollView panGestureRecognizer] setEnabled:NO];

Page-based application and gesture recognizer

I have created a page-based application in Xcode 4, for iPad iOS5.
When I run the app, I can see the pages in the book and can flip them back and forward,
by tap on the screen or by moving the finger from left to right, or right to left.
My problem is that no matter where I'm pressing in the screen, in the borders, the page turns.
I had managed to cancel the flip with fingers with this code:
for (UIGestureRecognizer *gR in self.pageViewController.gestureRecognizers)
{
if ([gR isKindOfClass:[UIPanGestureRecognizer class]])
{
[[gR view] removeGestureRecognizer:gR];
}
}
How can I define a specific area in the screen that when I tap on it, and only it, the page will turn?
I ask this because I put toolbar in the bottom of the screen and when I click on a button in the toolbar the page flips. I want to put 2 arrows on the screen that only when I press on them the page will flip.
Sorry if my explanation is a little bit rusty. Thank you all.
Cipramill's answer is correct -- here are more details.
The IOS documentation suggests adding new Views to delineate the areas where you wish the page turning gestures to be active, but this method is much simpler. Adding code to the default template set up by Xcode 4 in MQ1RootViewController.h and MQ1RootViewController.m:
Change interface line in MQ1RootViewController.h:
#interface MQ1RootViewController : UIViewController <UIPageViewControllerDelegate,
UIGestureRecognizerDelegate>
Add this code to the very bottom of viewDidLoad in MQ1RootViewController.m:
for (UIGestureRecognizer *gR in self.pageViewController.gestureRecognizers) {
gR.delegate = self;
}
Add this method to MQ1RootViewController.m:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch
{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]
|| [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
CGPoint point = [touch locationInView:self.view];
if(point.x < 100 || point.x > 924) return YES;
}
return NO;
}
Note that the "swipe" gesture is actually derived from a "pan" gesture by the page view controller object.
The above limits the gestures to the left and right edges of the screen. This allows gestures to be used to interact with objects in the center of the screen without accidentally changing the page with an errant swipe.
you could hook into the the gesture system and define which area to accept touches for.
In this explanation I assume your RootViewController has a UIPageViewController as a child VC:
-Set your root view controller to implement UIGestureRecognizerDelegate
-Take over all gesture recognizers for your pageVC in your RootViewControllers ViewDidLoad:
for (UIGestureRecognizer *gR in self.pageVC.gestureRecognizers) {
gR.delegate = self;
}
-Finally implement the gesture recognizer in your RootViewController and define which zones you want to ignore:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
CGPoint point = [touch locationInView:self.view];
//Examine point and return NO, if gesture should be ignored.
}
return YES;
}
Hope this helps

Resources