1

我想让用户抓住一个正在UIPanGestureRecognizer方法完成时动画的UIView。我目前能够使用touchesBegan和视图的表示层来停止视图并将其置于手指下方。但我希望用户能够重新触发UIPanGestureRecognizer方法,而无需抬起手指并将其替换到UIView上。在UIView动画时重新启动UIPanGestureRecognizer

我一直在研究这个挑战一个星期左右,并已通过各种搜索字符串在SO和其他地方,通过Ray Wenderlich的教程等阅读,但仍未找到解决方案。它看起来像我试图做同样的事情对这个问题似乎没有解决:

iOS - UIPanGestureRecognizer : drag during animation

我刚才一直在与UIView的动画块和还没有潜入CABasicAnimation工作。以某种方式改变下面的代码可以做我想做的事吗?

预先感谢您。

在FlingViewController.h:

#import <UIKit/UIKit.h> 

@interface FlingViewController : UIViewController <UIGestureRecognizerDelegate> 
{ 
    UIView *myView; 
} 

@property (nonatomic, weak) UIView *myView; 



@end 

在FlingViewController.m:

#import "FlingViewController.h" 
#import <QuartzCore/QuartzCore.h> 

@interface FlingViewController() 

@end 

@implementation FlingViewController 

@synthesize myView = _myView; 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    // Allocate and init view 
    myView = [[UIView alloc] initWithFrame:CGRectMake(self.view.center.x - 50, 
                 self.view.center.y - 50, 
                 100, 100)]; 

    // Set view background color 
    [myView setBackgroundColor:[UIColor purpleColor]]; 

    // Create pan gesture recognizer 
    UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] 
             initWithTarget:self action:@selector(handleGesture:)]; 

    // Add gesture recognizer to view 
    gesture.delegate = self; 
    [myView addGestureRecognizer:gesture]; 

    // Add myView as subview 
    [self.view addSubview:myView]; 
    NSLog(@"myView added"); 


} 

- (void)handleGesture:(UIPanGestureRecognizer *)recognizer 
{ 
    if ((recognizer.state == UIGestureRecognizerStateBegan) || 
     (recognizer.state == UIGestureRecognizerStateChanged)) 
    { 
     [recognizer.view.layer removeAllAnimations]; 

     CGPoint translation = [recognizer translationInView:self.view]; 
     recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, 
              recognizer.view.center.y + translation.y); 
     [recognizer setTranslation:CGPointMake(0, 0) inView:self.view]; 

    } 
    else if (recognizer.state == UIGestureRecognizerStateEnded) 
    { 
     CGPoint velocity = [recognizer velocityInView:self.view]; 
     CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y)); 
     CGFloat slideMult = magnitude/200; 

     float slideFactor = 0.1 * slideMult; 
     CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor), 
             recognizer.view.center.y + (velocity.y * slideFactor)); 
     finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width); 
     finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height); 

     [UIView animateWithDuration:slideFactor * 2 
           delay:0 
          options:(UIViewAnimationOptionCurveEaseOut| 
            UIViewAnimationOptionAllowUserInteraction | 
            UIViewAnimationOptionBeginFromCurrentState) 
         animations:^{ 
          recognizer.view.center = finalPoint; 
         } 
         completion:^(BOOL finished){ 
          NSLog(@"Animation complete"); 
         }]; 
    } 
} 


// Currently, this method will detect when user touches 
// myView's presentationLayer and will center that view under the finger 
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint touchPoint = [touch locationInView:self.view]; 

    if ([[myView.layer presentationLayer] hitTest:touchPoint]) 
    { 
     NSLog(@"Touched!"); 

     [myView.layer removeAllAnimations]; 

     myView.center = touchPoint; 

     // *** NOTE *** 
     // At this point, I want the user to be able to fling 
     // the view around again without having to lift the finger 
     // and replace it on the view; i.e. when myView is moving 
     // and the user taps it, it should stop moving and follow 
     // user's pan gesture again 
     // Similar to unresolved SO question: 
     // https://stackoverflow.com/questions/13234234/ios-uipangesturerecognizer-drag-during-animation 

    } 
} 


- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

@end 

回答

0

在情况下,它可以帮助别人,我发现,似乎工作得很好的解决方案的基础上,托马斯后悔/杰克的这个太问题回应:

CAAnimation - User Input Disabled

我使用两个UIPanGestureRecognizers移动UIView - 一个(手势/ handleGesture :)连接到UIView(myView),另一个(bigGesture/superGesture :)连接到该UIView的superview(bigView)。超级视图在动画时检测子视图表示层的位置。

目前唯一的问题是用户仍然可以通过在动画完成之前触摸myView动画的结束位置来获取动画视图。理想情况下,只有表示层位置才是用户可以与视图进行交互的地方。如果有人对防止过早交互有所了解,那将是值得赞赏的。

#import "FlingViewController.h" 
#import <QuartzCore/QuartzCore.h> 

@interface FlingViewController() 

@end 

@implementation FlingViewController 

@synthesize myView = _myView; 
@synthesize bigView = _bigView; 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    // *** USING A GESTURE RECOGNIZER ATTACHED TO THE SUPERVIEW APPROACH 
    // CAME FROM SO USER THOMAS RUED/JACK AT FOLLOWING LINK: 
    // https://stackoverflow.com/questions/7221688/caanimation-user-input-disabled 

    // Set up size for superView (bigView) 
    CGRect screenRect = [[UIScreen mainScreen] bounds]; 

    // Allocate big view 
    bigView = [[UIView alloc] initWithFrame:(screenRect)]; 

    [bigView setBackgroundColor:[UIColor greenColor]]; 

    [self.view addSubview:bigView]; 

    // Allocate and init myView 
    myView = [[UIView alloc] initWithFrame:CGRectMake(10, 10, 100, 100)]; 

    // Set view background color 
    [myView setBackgroundColor:[UIColor purpleColor]]; 

    // Create pan gesture recognizer 
    UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] 
             initWithTarget:self action:@selector(handleGesture:)]; 

    UIPanGestureRecognizer *bigGesture = [[UIPanGestureRecognizer alloc] 
              initWithTarget:self action:@selector(superGesture:)]; 

    // Add gesture recognizer to view 
    gesture.delegate = self; 
    bigGesture.delegate = self; 
    [myView addGestureRecognizer:gesture]; 
    [bigView addGestureRecognizer:bigGesture]; 

    // Add myView as subview of bigView 
    [bigView addSubview:myView]; 
    NSLog(@"myView added"); 

} 

// This gesture recognizer is attached to the superView, 
// and will detect myView's presentation layer while animated 
- (void)superGesture:(UIPanGestureRecognizer *)recognizer 
{  
    CGPoint location = [recognizer locationInView:self.view]; 

    for (UIView* childView in recognizer.view.subviews) 
    { 
     CGRect frame = [[childView.layer presentationLayer] frame]; 

     if (CGRectContainsPoint(frame, location)) 
     // ALTERNATE 'IF' STATEMENT; BOTH SEEM TO WORK: 
     //if ([[childView.layer presentationLayer] hitTest:location]) 
     { 
      NSLog(@"location = %.2f, %.2f", location.x, location.y); 
      [childView.layer removeAllAnimations]; 
      childView.center = location; 
     } 

     if ((recognizer.state == UIGestureRecognizerStateEnded) && 
      (CGRectContainsPoint(frame, location))) 
     { 
      CGPoint velocity = [recognizer velocityInView:self.view]; 
      CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y)); 
      CGFloat slideMult = magnitude/200; 

      float slideFactor = 0.1 * slideMult; 
      CGPoint finalPoint = CGPointMake(childView.center.x + (velocity.x * slideFactor), 
              childView.center.y + (velocity.y * slideFactor)); 
      finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width); 
      finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height); 

      [UIView animateWithDuration:slideFactor * 2 
            delay:0 
           options:(UIViewAnimationOptionCurveEaseOut| 
             UIViewAnimationOptionAllowUserInteraction | 
             UIViewAnimationOptionBeginFromCurrentState) 
          animations:^{ 
           childView.center = finalPoint; 
          } 
          completion:^(BOOL finished){ 
           NSLog(@"Big animation complete"); 
          }]; 
     } 
    } 
} 

// This gesture recognizer is attached to myView, 
// and will handle movement when myView is not animating 
- (void)handleGesture:(UIPanGestureRecognizer *)recognizer 
{ 

    if ((recognizer.state == UIGestureRecognizerStateBegan) || 
     (recognizer.state == UIGestureRecognizerStateChanged)) 
    { 
     [recognizer.view.layer removeAllAnimations]; 

     CGPoint translation = [recognizer translationInView:self.view]; 
     recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, 
              recognizer.view.center.y + translation.y); 
     [recognizer setTranslation:CGPointMake(0, 0) inView:self.view]; 

    } 
    else if (recognizer.state == UIGestureRecognizerStateEnded) 
    { 
     CGPoint velocity = [recognizer velocityInView:self.view]; 
     CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y)); 
     CGFloat slideMult = magnitude/200; 

     float slideFactor = 0.1 * slideMult; 
     CGPoint finalPoint = CGPointMake(recognizer.view.center.x + (velocity.x * slideFactor), 
             recognizer.view.center.y + (velocity.y * slideFactor)); 
     finalPoint.x = MIN(MAX(finalPoint.x, 0), self.view.bounds.size.width); 
     finalPoint.y = MIN(MAX(finalPoint.y, 0), self.view.bounds.size.height); 

     [UIView animateWithDuration:slideFactor * 2 
           delay:0 
          options:(UIViewAnimationOptionCurveEaseOut| 
            UIViewAnimationOptionAllowUserInteraction | 
            UIViewAnimationOptionBeginFromCurrentState) 
         animations:^{ 
          recognizer.view.center = finalPoint; 
         } 
         completion:^(BOOL finished){ 
          NSLog(@"Animation complete"); 
         }]; 
    } 

} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

@end