UITapGestureRecognizer and UIPanGestureRecognizer - ios

I want to create and see a uiimageview when i tap the screen.
Before i lift the finger, i want to move the uiimageview around the screen and the image set only when i take the finger off. Heres what i did:
- (IBAction)tap:(UITapGestureRecognizer *)recognizer {
CGPoint location = [recognizer locationInView:self.view];
UIImageView *circle = [[UIImageView alloc] initWithFrame:CGRectMake(location.x, location.y, 50, 50)];
circle.userInteractionEnabled = YES;
[circle setImage:[UIImage imageNamed:#"monkey_1.png"]];
[self.view addSubview:circle];
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:circle action:nil];
[recognizer requireGestureRecognizerToFail:pan];
CGPoint translation = [pan translationInView:circle];
pan.view.center = CGPointMake(pan.view.center.x + translation.x, pan.view.center.y + translation.y);
[pan setTranslation:CGPointMake(0, 0) inView:self.view];
}

You can do this with just an UIPanGestureRecognizer or an UILongPressGestureRecognizer. In the gesture handling method, check the state property of the recognizer, and show your image when it's UIGestureRecognizerStateEnded (i.e. when the user lifts the finger from the screen). E.g.:
- (void)handleGesture:(UILongPressGestureRecognizer *)recognizer {
if(recognizer.state == UIGestureRecognizerStateEnded) {
// gesture ended: show the image
}
else if(recognizerState == UIGestureRecognizerStateBegan) {
// this code runs when the gesture is started.
}
else if(recognizerState == UIGestureRecognizerStateChanged) {
// gesture is in progress
}
}

Related

Gesture recognizer with Voice Over active

I developed an application which allows to the user to draw his finger signature in a canvas.
This feature is implemented using UIPanGestureRecognizer with a specific target action to draw a line in a UIView, but when the “Voice Over” is active the gesture recognizer action is not triggered anymore.
Gesture initialize code
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];
Gesture action code
- (void)pan:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self];
CGPoint midPoint = midpoint(previousPoint, currentPoint);
if (pan.state == UIGestureRecognizerStateBegan)
{
[path moveToPoint:currentPoint];
}
else if (pan.state == UIGestureRecognizerStateChanged)
{
[path addQuadCurveToPoint:midPoint controlPoint:previousPoint];
}
previousPoint = currentPoint;
[self setNeedsDisplay];
}
Is there any way to draw a line in a view using gesture with “Voice Over” active?
Thanks and regards!
I resolved my problem setting both isAccessibilityElement and accessibilityTraits properties for UIView canvas:
canvasView.isAccessibilityElement = YES;
canvasView.accessibilityTraits = UIAccessibilityTraitAllowsDirectInteraction;

Dragging UICollectionViewCell relative to finger

I'm trying to drag a UICollectionViewCell relative to finger. This does not mean reordering the CollectionView, I just want the cell to be dragable. The current code works on a UIView, but not on a cell.
Here is what I add to the cell:
UIPanGestureRecognizer* drag;
drag = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragging:)];
[cell addGestureRecognizer:drag];
And here is the method that is invoked. The method is definitely activated, but it does not drag the cell.
-(void)dragging:(UIPanGestureRecognizer *)gesture
{
NSLog(#"dragging");
CGPoint panCoord;
if(gesture.state == UIGestureRecognizerStateBegan)
{
NSLog(#"Received a pan gesture");
panCoord = [gesture locationInView:gesture.view];
}
CGPoint newCoord = [gesture locationInView:gesture.view];
float dX = newCoord.x-panCoord.x;
float dY = newCoord.y-panCoord.y;
gesture.view.frame = CGRectMake(gesture.view.frame.origin.x+dX, gesture.view.frame.origin.y+dY, gesture.view.frame.size.width, gesture.view.frame.size.height);
}

Cancel multiple touches on the View

I am adding UIPanGestureRecogniser to drag and drop images in a view.I want to drag only one image at a time.but I am able to drag two images at a time.which should not happen.
I am stuck with this bug since morning.I tried all the ways i found on google.
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view setMultipleTouchEnabled:NO];
for(UIImageView *iView in self.movableArray){
if ([iView isMemberOfClass:[UIImageView class]]){
UIPanGestureRecognizer * recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
[iView addGestureRecognizer:recognizer];
[iView setUserInteractionEnabled:YES];
recognizer.delegate = self;
}
}
}
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer {
[gameView bringSubviewToFront:[(UIPanGestureRecognizer *)recognizer view]];
CGPoint translation = [recognizer translationInView:gameView];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:gameView];
self.dragObjectImageView = (UIImageView*)recognizer.view;
if(recognizer.state == UIGestureRecognizerStateBegan){
int ind = [self.movableArray indexOfObject:self.dragObjectImageView];
for(int i = 0 ; i < [self.movableArray count] ; i ++){
if( i != ind ){
[[self.movableArray objectAtIndex:i] removeGestureRecognizer:recognizer];
}
}
self.homePosition = self.dragObjectImageView.frame;
}
if (recognizer.state == UIGestureRecognizerStateEnded) {
CGPoint touchPoint = [recognizer locationInView:gameView];
for (UIImageView *iView in self.staticArray) {
if ([iView isMemberOfClass:[UIImageView class]]) {
if (touchPoint.x > iView.frame.origin.x &&
touchPoint.x < iView.frame.origin.x + iView.frame.size.width &&
touchPoint.y > iView.frame.origin.y &&
touchPoint.y < iView.frame.origin.y + iView.frame.size.height)
{
self.dropTargetImageView = iView;
}
}
}
if(self.dragObjectImageView.tag == self.dropTargetImageView.tag){
self.dragObjectImageView.frame = CGRectMake(self.dropTargetImageView.frame.origin.x, self.dropTargetImageView.frame.origin.y + self.dropTargetImageView.frame.size.height/2 - 15, self.dragObjectImageView.frame.size.width, self.dragObjectImageView.frame.size.height);
[self.dragObjectImageView removeGestureRecognizer:recognizer];
}
}else{
self.dragObjectImageView.frame = self.homePosition;
}
}
}
This happens because you are adding one UIPanGestureRecognizer for each of your imageViews. Try adding only one to your self.view (and have your imageViews to setUserInteractionEnabled:NO, otherwise they will trap the touch). Also put
recognizer.maximumNumberOfTouches = 1;
Before you add it to your view. All you have to do now is to test which image view should be dragged in your handlePan method. You should check the recognizer state and when it turns to UIGestureRecognizerStateBegan you should save which imageView is being dragged. Then as the state is UIGestureRecognizerStateChanged just drag the view around. The most general way you can find out which view was touched (as i don't know your full view hierarchy) would be to do something like:
NSUInteger index = [self.movableArray indexOfObjectPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop)){
UIView* hitTest = (UIView*)obj;
return [hitTest pointInside:firstTouch withEvent:nil];
}];
if ( index != NSNotFound )
self.draggingView = self.moveableArray[index];
else
self.draggingView = nil;
Then of course if self.draggingView is nil you would do nothing when the user is panning around.
You should create a mechanism to setUserInteractionEnable = NO when your
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer;
Is called on the other images. You can either do that, or disable the others UIPanGestureRecognizer, like: myPanGestureRecognizer.enabled = NO;
A quick example:
- (IBAction)handlePan:(UIPanGestureRecognizer *)recognizer
{
UIImageView *currentDraggedImageView = recognizer.view;
// Based on this, you can iterate again on your UIImageViews and disable them.
// Once your work is done with gesture recogniser, you can re-enable them.
}

iOS: dragGesture don't move element

In my app I have this code to drag an object
I set my gesture:
UILongPressGestureRecognizer *downwardGesture = [[UILongPressGestureRecognizer new] initWithTarget:self action:#selector(dragGestureChanged:)];
downwardGesture.minimumPressDuration = 0.2;
[grid_element addGestureRecognizer:downwardGesture];
for (UILongPressGestureRecognizer *gestureRecognizer in self.view.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:downwardGesture];
}
and in my method:
- (void) dragGestureChanged:(UILongPressGestureRecognizer*)gesture{
UIImageView *imageToMove;
CGPoint pointInSelfView;
if (gesture.state == UIGestureRecognizerStateBegan)
{
dragging = TRUE;
CGPoint location = [gesture locationInView:grid_element];
NSIndexPath *selectedIndexPath = [grid_element indexPathForItemAtPoint:location];
if (selectedIndexPath==nil) {
dragging = FALSE;
return;
}
indexToHide = selectedIndexPath.row;
imageToMove = [[UIImageView alloc]initWithImage:[UIImage imageNamed:#"image_1.png"]];
[self.view addSubview:imageToMove];
pointInSelfView = [gesture locationInView:self.view];
[imageToMove setCenter:pointInSelfView];
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
pointInSelfView = [gesture locationInView:self.view];
[imageToMove setCenter:pointInSelfView];
}
else if (gesture.state == UIGestureRecognizerStateEnded ||
gesture.state == UIGestureRecognizerStateCancelled ||
gesture.state == UIGestureRecognizerStateFailed)
{
dragging = FALSE;
}
}
it work in UIGestureRecognizerStateBegan, then imageToMove is added in self.view in the correct position but imageToMove don't drag in UIGestureRecognizerStateChanged; I show a NSLog for pointInSelfView in UIGestureRecognizerStateChanged and it changes correctly; where is the problem?
EDIT
if I use imageToMove as IBOutlet it work fine, but I don't understand the difference.
If you are using ARC, the iOS system is releasing object-imageToMove.
Creating a property with retain attribute, makes system retains the object and hence it moves.
The only thing I am confused is why there is no error in [imageToMove setCenter:pointInSelfView];. There should be an error saying - message is sent to deallocated instance. But I am pretty sure that the problem is due to memory release of imageToMove.

How to detect or define the orientation of a pinch gesture with UIPinchGestureRecognizer?

I'm using UIPinchGestureRecognizer to detect pinch gestures, something like:
- (void) initPinchRecon {
UIPinchGestureRecognizer *pinchRecognizer = [[[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:#selector(Perform_Pinch:)] autorelease];
[self addGestureRecognizer:pinchRecognizer];
[pinchRecognizer setScale:20.0f];
}
- (void) Perform_Pinch:(UIPinchGestureRecognizer*)sender{
NSLog(#"PINCH");
}
And it works well to detect a simple pinch gesture: It's possible to determine (or define myself) the angle or orientation of the pinch gesture ?, for example, to differentiate between an horizontal and an vertical pinch gesture ?
A very simple solution is to implement the gesture handler like this:
-(void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer {
if (recognizer.state != UIGestureRecognizerStateCancelled) {
if (recognizer.numberOfTouches == 2) {
CGPoint firstPoint = [recognizer locationOfTouch:0 inView:recognizer.view];
CGPoint secondPoint = [recognizer locationOfTouch:1 inView:recognizer.view];
CGFloat angle = atan2(secondPoint.y - firstPoint.y, secondPoint.x - firstPoint.x);
// handle the gesture based on the angle (in radians)
}
}

Resources