Draggable UITextField enters editing when it shouldn't - ios

I'm developing an iOS6 app for iPad. I have coded a subclass of UITextField that enables the user to drag, pinch and rotate the field around the view. The problem is that if you pinch the field with no rotation, after finishing the gesture, it enters in editing mode. This should not happen, and I've added some lines that disable that, but it doesn't stop. Here I my code:
- (BOOL) canBecomeFirstResponder{
if (gesturing==YES) {
return NO;
}else return YES;
}
- (void) tapDetected:(UITapGestureRecognizer*) pinchRecognizer {
if (gesturing==NO) {
[self becomeFirstResponder];
}
}
- (void) pinchDetected:(UIPinchGestureRecognizer*) pinchRecognizer {
CGFloat scale = pinchRecognizer.scale;
self.font = [self.font fontWithSize:self.font.pointSize*(scale)];
//self.transform = CGAffineTransformScale(self.transform, scale, scale);
[self sizeToFit];
pinchRecognizer.scale = 1.0;
if (pinchRecognizer.state == UIGestureRecognizerStateChanged) {
gesturing =YES;
}
if (pinchRecognizer.state == UIGestureRecognizerStateBegan) {
gesturing =YES;
}
if (pinchRecognizer.state == UIGestureRecognizerStateEnded) {
gesturing =NO;
}
}
- (void) panDetected:(UIPanGestureRecognizer *)panRecognizer {
CGPoint translation = [panRecognizer translationInView:self.superview];
CGPoint imageViewPosition = self.center;
imageViewPosition.x += translation.x;
imageViewPosition.y += translation.y;
self.center = imageViewPosition;
[panRecognizer setTranslation:CGPointZero inView: self.superview];
if (panRecognizer.state == UIGestureRecognizerStateChanged) {
gesturing=YES;
}
if (panRecognizer.state == UIGestureRecognizerStateEnded) {
gesturing=NO;
}
}
- (void) rotationDetected:(UIRotationGestureRecognizer *)rotationRecognizer{
CGFloat angle = rotationRecognizer.rotation;
self.transform = CGAffineTransformRotate(self.transform, angle);
rotationRecognizer.rotation = 0.0;
if (rotationRecognizer.state == UIGestureRecognizerStateChanged) {
gesturing = YES;
}
if (rotationRecognizer.state == UIGestureRecognizerStateEnded) {
gesturing = NO;
}
}
- (BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}

I bydefault value of gesturing is NO, if you don't initialize it to YES. Have debugged and figured out which gesture recognizer is detected first whenever you try to apply pinch?
You support simultaneous gesture recognition and hence when you put to apply pinch, your finger's touch may get detected as pan. If it is the case then if(gesturing == NO) condition in tapDetected: method gets satisfied and your textField becomes first responder.

Related

in Xcode 6, scale value from image diff with value in UIPinchGestureRecognizer

Now i develop an app that all user drag, rotate and scale image inside uiview. but when i want to save image view data like rotate value and scale value. i found scale value from [[img.layer valueForKeyPath:#"transform.scale"] floatValue] diff with scale that i found. the scale value is like below.
-(void)scale:(id)sender {
if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateBegan) {
_lastScale = 1.0;
}
CGFloat scale = 1.0 - (_lastScale - [(UIPinchGestureRecognizer*)sender scale]);
//CGFloat scale = 1.0 + ([(UIPinchGestureRecognizer *)sender scale] - _lastScale);
CGAffineTransform currentTransform = self.transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[self setTransform:newTransform];
_lastScale = [(UIPinchGestureRecognizer*)sender scale];
CGFloat size = [[self.layer valueForKeyPath:#"transform.scale"] floatValue];
self.saveScale = _lastScale;
NSLog(#"Scale %f %f",_lastScale, size);
}
so the save scale value is diff with [[img.layer valueForKeyPath:#"transform.scale"].
PLEASE HELP!!!
Declare Variable -> CGFloat currentScale;
- (void) handlePinches:(UIPinchGestureRecognizer*)paramSender{
if (paramSender.state == UIGestureRecognizerStateEnded){
currentScale = paramSender.scale;
} else if (paramSender.state == UIGestureRecognizerStateBegan &&
self.currentScale != 0.0f){
paramSender.scale = currentScale;
}
if (paramSender.scale != NAN &&
paramSender.scale != 0.0){
paramSender.view.transform =
CGAffineTransformMakeScale(paramSender.scale,
paramSender.scale);
}
}
try this
You need to add Delegate
#interface MyClass : MySuperClass <UIGestureRecognizerDelegate>
- (void)viewDidLoad
{
[super viewDidLoad];
// set up the image view
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"someImage"]];
[imageView setBounds:CGRectMake(0.0, 0.0, 120.0, 120.0)];
[imageView setCenter:self.view.center];
[imageView setUserInteractionEnabled:YES]; // <--- This is very important
// create and configure the pinch gesture
UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinchGestureDetected:)];
[pinchGestureRecognizer setDelegate:self];
[imageView addGestureRecognizer:pinchGestureRecognizer];
// create and configure the rotation gesture
UIRotationGestureRecognizer *rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:#selector(rotationGestureDetected:)];
[rotationGestureRecognizer setDelegate:self];
[imageView addGestureRecognizer:rotationGestureRecognizer];
[self.view addSubview:imageView]; // add the image view as a subview of the view controllers view
}
add this two methods
- (void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat scale = [recognizer scale];
[recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
[recognizer setScale:1.0];
}
}
- (void)rotationGestureDetected:(UIRotationGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat rotation = [recognizer rotation];
[recognizer.view setTransform:CGAffineTransformRotate(recognizer.view.transform, rotation)];
[recognizer setRotation:0];
}
}
after add this delegate method
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
you can handle also pangesture using this method.
add pan gesture in to image.
self.panResizeGesture = [[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(handlePanGestures:)];
imgPatSelect.userInteractionEnabled = YES;
[imgPatSelect addGestureRecognizer:self.panResizeGesture];
add this method to handle pan.
- (void) handlePanGestures:(UIPanGestureRecognizer*)recognizer{
CGPoint translation = [recognizer translationInView:self.view];
CGRect recognizerFrame = recognizer.view.frame;
recognizerFrame.origin.x += translation.x;
recognizerFrame.origin.y += translation.y;
// Check if UIImageView is completely inside its superView
if (CGRectContainsRect(self.view.bounds, recognizerFrame)) {
recognizer.view.frame = recognizerFrame;
}
// Else check if UIImageView is vertically and/or horizontally outside of its
// superView. If yes, then set UImageView's frame accordingly.
// This is required so that when user pans rapidly then it provides smooth translation.
else {
// Check vertically
if (recognizerFrame.origin.y < self.view.bounds.origin.y) {
recognizerFrame.origin.y = 0;
}
else if (recognizerFrame.origin.y + recognizerFrame.size.height > self.view.bounds.size.height) {
recognizerFrame.origin.y = self.view.bounds.size.height - recognizerFrame.size.height;
}
// Check horizantally
if (recognizerFrame.origin.x < self.view.bounds.origin.x) {
recognizerFrame.origin.x = 0;
}
else if (recognizerFrame.origin.x + recognizerFrame.size.width > self.view.bounds.size.width) {
recognizerFrame.origin.x = self.view.bounds.size.width - recognizerFrame.size.width;
}
}
// Reset translation so that on next pan recognition
// we get correct translation value
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}

UIAttachmentBehavior doesn't work. UIDynamicAnimator

I am having trouble using initWithItem:attachedToItem: Initializes an attachment behavior that connects the center point of a dynamic item to the center point of another dynamic item.
But when I changed the center point of topview using method pan,only the topview moved around,I can't get the other view to move.Isn't it should be moving together?
(BTW I am trying to implement a pile of cards and move around all together when I pan the card in the top.)
-(void)pinch:(UIPinchGestureRecognizer *)gesture
{
if(gesture.state == UIGestureRecognizerStateChanged){
CGPoint pinchCen = [gesture locationInView:self.cardArea];
if (gesture.scale <= 0.5 && !self.pileStat) {
self.pileStat = !self.pileStat;
NSUInteger number = [self.cardViews count];
UIView *topView = [self.cardViews lastObject];
[topView addGestureRecognizer:[[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(pan:)]];
for (int i = 0; i < number;i++) {
UIView *cardView = self.cardViews[i];
[UIView animateWithDuration:0.5 animations:^{cardView.center = CGPointMake(pinchCen.x+i%10*0.5, pinchCen.y+i%10*0.5);} completion:^(BOOL finished){
if(i != number - 1){
UIAttachmentBehavior *attach = [[UIAttachmentBehavior alloc]initWithItem:cardView attachedToItem:topView];
[self.animator addBehavior:attach];
}
}];
}
}
else if(gesture.scale > 1.5 && self.pileStat)
{
self.pileStat = !self.pileStat;
}
}else if (gesture.state == UIGestureRecognizerStateEnded){
gesture.scale = 1.0f;
}
}
-(void)pan:(UIPanGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateChanged || UIGestureRecognizerStateEnded) {
UIView *topView = [self.cardViews lastObject];
CGPoint trans = [gesture translationInView:self.cardArea];
topView.center = CGPointMake(trans.x+topView.center.x, trans.y+topView.center.y);
[gesture setTranslation:CGPointMake(0, 0) inView:self.cardArea];
}
}
setCenter does not play nice with UIDynamicAnimator. Instead of changing the center coordinate of your top view, you should use another UIAttachmentBehavior that you attach to your touch. Replace your pan gesture handler with this method:
//Add a variable in your interface or header section called "touchAttachment" of type UIAttachmentBehavior
- (void) pan: (UIPanGestureRecognizer *) sender{
UIView* topCard = [self.cardViews lastObject];
if (sender.state == UIGestureRecognizerStateBegan){
_touchAttachment = [[UIAttachmentBehavior alloc] initWithItem:topCard
attachedToAnchor: [sender locationInView:self.view]];
[self.animator addBehavior:_touchAttachment];
}
else if (sender.state == UIGestureRecognizerStateChanged){
[_touchAttachment setAnchorPoint: [sender locationInView: self.view]];
}
else if (sender.state == UIGestureRecognizerStateEnded){
[self.animator removeBehavior: _touchAttachment];
_touchAttachment = nil;
}
}
Make sure you add the "touchAttachment" variable.
Hope it helps :)

UIPanGestureRecognizer and UIPinchGestureRecogizer for zoom in AND move with bounce-pull back animation

I have UIImageView inside UIView.
please assume the user can only zoomin (not in this code).
if the uiimage is bigger the UIView, I need the animation that pull back the uiimage, like in the facebook app.
meaning , If user move the UIImageView up..when he lift the finger the UIImageView is pullback to cover the empty space on the bottom.
I tried to play with it, but..no luck.
thanks in advance
-(void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGFloat scale = [recognizer scale];
[recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
[recognizer setScale:1.0];
}
}
- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:recognizer.view];
[recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return ![gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]];
}
that one should work if your image is bigger than its container:
- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
UIGestureRecognizerState state = [recognizer state];
if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [recognizer translationInView:recognizer.view];
[recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
else if(state==UIGestureRecognizerStateEnded){
UIView *imageView = recognizer.view;
UIView *container = imageView.superview;
CGFloat targetX = CGRectGetMinX(imageView.frame);
CGFloat targetY = CGRectGetMinY(imageView.frame);
if(targetX>0){
targetX = 0;
}else if(CGRectGetMaxX(imageView.frame)<CGRectGetWidth(container.bounds)){
targetX = CGRectGetWidth(container.bounds)-CGRectGetWidth(imageView.frame);
}
if(targetY>0){
targetY = 0;
}else if(CGRectGetMaxY(imageView.frame)<CGRectGetHeight(container.bounds)){
targetY = CGRectGetHeight(container.bounds)-CGRectGetHeight(imageView.frame);
}
[UIView animateWithDuration:0.3 animations:^{
imageView.frame = CGRectMake(targetX, targetY, CGRectGetWidth(imageView.frame), CGRectGetHeight(imageView.frame));
}];
}
}

UIPanGestureRecognizer interfering with scroll

I have a scroll view with 3 view controllers that I want to swipe between. However, one of my view controllers has a UIPanGestureRecognizer and this stops the scrollview from working. This is the code for the pan:
- (void)pan:(UIPanGestureRecognizer *)aPan; // When pan guesture is recognised
{
CGPoint location = [aPan locationInView:self.view]; // Location of finger on screen
CGRect secondRect = CGRectMake(210.0, 45.0, 70.0, 325.0); // Rectangles of maximimum bar area
CGRect minuteRect = CGRectMake(125.0, 45.0, 70.0, 325.0);
CGRect hourRect = CGRectMake(41.0, 45.0, 70.0, 325.0);
if (CGRectContainsPoint(secondRect, location)) { // If finger is inside the 'second' rectangle
CGPoint currentPoint = [aPan locationInView:self.view];
currentPoint.y -= 80; // Make sure animation doesn't go outside the bars' rectangle
if (currentPoint.y < 0) {
currentPoint.y = 0;
}
else if (currentPoint.y > 239) {
currentPoint.y = 239;
}
currentPoint.y = 239.0 - currentPoint.y;
CGFloat pointy = currentPoint.y - fmod(currentPoint.y, 4.0);
[UIView animateWithDuration:0.01f // Animate the bars to rise as the finger moves up and down
animations:^{
CGRect oldFrame = secondBar.frame;
secondBar.frame = CGRectMake(oldFrame.origin.x, (oldFrame.origin.y - (pointy - secondBar.frame.size.height)), oldFrame.size.width, (pointy));
}];
CGFloat result = secondBar.frame.size.height - fmod(secondBar.frame.size.height, 4.0);
secondInt = (result / 4.0); // Update labels with new time
self->secondLabel.text = [NSString stringWithFormat:#"%02d", secondInt];
}
}
Basically, this code allows the user to drag their finger up and down the screen, and change the height of a uiview. Therefore, I only need the up/down pan gesture for this and only the left/right pan gestures for the scroll view.
Does anyone have any idea how I can do this?
Your scrollview has a property called panGestureRecognizer. You can create a delegate for your own UIPanGestureRecognizer, and implement this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if(otherGestureRecognizer == myScrollView.panGestureRecognizer) {
return YES;
} else {
return NO;
}
}
UIPanGestureRecognizer contains a delegate method - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch that you can return YES or NO to let/prevent the pan gesture from receiving the touch.
Within that method, you could write something like:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
CGPoint velocity = [gestureRecognizer velocityInView:yourView];
if(velocity.x > 0)
{
NSLog(#"gesture went right"); // return NO
}
else if (velocity.x < 0)
{
NSLog(#"gesture went left"); // return NO
}
if (velocity.y > 0)
{
NSLog(#"gesture went down"); // return YES
}
else if (velocity.y < 0)
{
NSLog(#"gesture went up"); // return YES
}
}
Admittedly, that probably isn't the cleanest implementation. You're leaving an open door for mixed gestures. So just make sure to watch for that.

Not able to move two images using uipangesturerecogniser

I want to move two images with same UIPanGestureRecognizer ,
I am able to move the first image, but as soon as I try to move the second image the first one goes back to its original position. I want the first image to retain it's after changed position.
-(void) viewWillAppear:(BOOL)animated
{
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanSuper:)];
[self.view addGestureRecognizer:pan];
}
- (void)handlePanSuper:(UIPanGestureRecognizer *)sender
{
static UIImageView *viewToMove;
static CGPoint originalCenter;
if (sender.state == UIGestureRecognizerStateBegan)
{
CGPoint location = [sender locationInView:self.view];
if (CGRectContainsPoint(self.imageView.frame, location))
{
viewToMove = imageView;
originalCenter = viewToMove.center;
}
else if (CGRectContainsPoint(self.image2.frame, location))
{
viewToMove = image2;
originalCenter = viewToMove.center;
}
else
{
viewToMove = nil;
}
if (viewToMove)
{
viewToMove.alpha = 0.8;
[viewToMove.superview bringSubviewToFront:viewToMove];
NSLog(#"hi i am being touched.");
}
}
if (sender.state == UIGestureRecognizerStateChanged && viewToMove != nil)
{
CGPoint translation = [sender translationInView:self.view];
viewToMove.center = CGPointMake(originalCenter.x + translation.x, originalCenter.y + translation.y);
}
else if ((sender.state == UIGestureRecognizerStateEnded ||
sender.state == UIGestureRecognizerStateFailed ||
sender.state == UIGestureRecognizerStateCancelled) && viewToMove != nil)
{
// do whatever post dragging you want, e.g.
// snap the piece into place
// CGPoint center = viewToMove.center;
//viewToMove.center = center;
viewToMove.alpha = 1.0;
viewToMove = nil;
}
}
You are setting your gesture recognizer in your superView. Why? You could set it inside the views that you are trying to move, it's easier and less likely to strange behaviors I edited your code, see below (not tested)
-(void) viewWillAppear:(BOOL)animated
{
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanSuper:)];
self.imageView.userInteractionEnabled = self.image2.userInteractionEnabled = YES;
[self.imageView addGestureRecognizer:pan];
[self.image2 addGestureRecognizer:pan];
}
- (void)handlePanSuper:(UIPanGestureRecognizer *)sender
{
UIImageView *viewToMove = (UIImageView*)sender.view;
CGPoint originalCenter = viewToMove.center;
if (sender.state == UIGestureRecognizerStateBegan)
{
CGPoint location = [sender locationInView:self.view];
viewToMove.alpha = 0.8;
[viewToMove.superview bringSubviewToFront:viewToMove];
NSLog(#"hi i am being touched.");
}
else if (sender.state == UIGestureRecognizerStateChanged)
{
CGPoint translation = [sender translationInView:self.view];
viewToMove.center = CGPointMake(originalCenter.x + translation.x, originalCenter.y + translation.y);
}
else if ((sender.state == UIGestureRecognizerStateEnded ||
sender.state == UIGestureRecognizerStateFailed ||
sender.state == UIGestureRecognizerStateCancelled))
{
// do whatever post dragging you want, e.g.
// snap the piece into place
// CGPoint center = viewToMove.center;
//viewToMove.center = center;
viewToMove.alpha = 1.0;
viewToMove = nil;
}
}
Please try this, and let me know if worked.

Resources