【问题标题】:Restarting UIPanGestureRecognizer while UIView is animating在 UIView 动画时重新启动 UIPanGestureRecognizer
【发布时间】:2013-07-22 16:43:22
【问题描述】:

我试图让用户在完成 UIPanGestureRecognizer 方法时获取正在动画的 UIView。我目前能够使用 touchesBegan 和视图的表示层来停止视图并将其居中放置在手指下方。但我希望用户能够重新触发 UIPanGestureRecognizer 方法,而无需抬起手指并在 UIView 上替换它。

我已经为这个挑战工作了一周左右,并且在 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

【问题讨论】:

    标签: cocoa-touch animation uiview uipangesturerecognizer touchesbegan


    【解决方案1】:

    如果它对其他人有帮助,根据 Thomas Rued/Jack 对这个 SO 问题的回答,我找到了一个似乎效果很好的解决方案:

    CAAnimation - User Input Disabled

    我正在使用两个 UIPanGestureRecognizer 来移动 UIView - 一个 (gesture/handleGesture:) 连接到 UIView (myView),另一个 (bigGesture/superGesture:) 连接到该 UIView 的超级视图 (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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-25
      • 2018-12-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多