选择不同的 UIPanGestureRecognizer 触摸

Choose different UIPanGestureRecognizer touches

好的,我有一个带有左侧菜单和右侧视图控制器的应用程序,它们由 UIPanGestureRecognizer 控制。因此,当用户滑动屏幕边缘的边框 (20px) 时,它会导航。

在设置视图控制器中,我有 UISwitches 控制其他各种东西,但其中之一我想控制 UIPanGestureRecognizer 将进行多少次触摸。

开关设置正确,将用户默认值发送到另一个视图控制器,但在它的接收端,它不会读取用户选择的内容。

UIPanGestureRecognizer * pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureCallback:)];

//Switch for SwipeNav
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
BOOL switchOn = [userDefaults boolForKey:@"SwipeNav"];

if (switchOn) {
    // 2 Finger SwipeNav
    [pan setMinimumNumberOfTouches:2];
    [pan setMaximumNumberOfTouches:2];

}else{
    [pan setMinimumNumberOfTouches:1];
    [pan setMaximumNumberOfTouches:1];
}
[pan setDelegate:self];
[self.view addGestureRecognizer:pan];

我怎样才能做到这样,当开关打开时,它使用 2 次触摸来导航,关闭它时就像正常一样?

我们将不胜感激任何帮助。谢谢。

更新了设置同步代码。

    if (swipe){
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setBool:self.swipe.on forKey:@"SwipeNav"];
    [userDefaults synchronize];

    if ([swipe isOn]) {
        [swipe setOn:YES animated:YES];
        [self.tableView reloadData];
        [[UIApplication sharedApplication] reloadInputViews];

    } else {
        [swipe setOn:NO animated:YES];
        [self.tableView reloadData];
        [[UIApplication sharedApplication] reloadInputViews];
    }
}

我创建了一个新项目并尝试重现您遇到的问题,一切似乎都按预期进行。当开关打开时,您需要两个按钮来平移,而当开关关闭时,您只需要一个。让我知道这是否为您指明了正确的方向。您的代码似乎是正确的。

我从 How to use UIPanGestureRecognizer to move object? iPhone/iPad

复制粘贴了 handlePan 函数

以编程方式创建所有内容并复制粘贴您的代码以保存开关状态。这是来自两个 UIViewControllers

的代码
//
//  ViewController.m
//  WhosebugSwitch
//
//  
// 
//

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic,strong) UIButton *myButton;
@property (nonatomic,strong) UISwitch *switchOn;


@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.myButton = [[UIButton alloc]initWithFrame:CGRectMake(10, 100, 150, 150)];
    self.switchOn = [[UISwitch alloc]initWithFrame:CGRectMake(10, 300, 100, 100)];
    self.myButton.backgroundColor =[UIColor grayColor];
    [self.myButton setTitle:@"Click Me" forState:UIControlStateNormal];
    [self.myButton addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:self.switchOn];
    [self.view addSubview:self.myButton];
    // Do any additional setup after loading the view, typically from a nib.
}

-(void)click:(UIButton *)sender
{
    [self performSegueWithIdentifier:@"NextViewController" sender:self];
}


-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{

    if(self.switchOn.on){
        NSLog(@"switch is on");
    }else{
        NSLog(@"switch is off");
    }
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setBool:self.switchOn.on forKey:@"SwipeNav"];
    [userDefaults synchronize];

}

@end

//////

#import "SecondViewController.h"
@interface SecondViewController() <UIGestureRecognizerDelegate>

@property (strong,nonatomic) UIView *myView;

@end


@implementation SecondViewController



-(void)viewDidLoad
{
    [super viewDidLoad];
    self.myView = [[UIView alloc]initWithFrame:CGRectMake(10, 10, 200, 200)];
    self.myView.backgroundColor = [UIColor redColor];
    [self.view addSubview:self.myView];

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];

    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"SwipeNav"];

    if (switchOn) {
        // 2 Finger SwipeNav
        [pan setMinimumNumberOfTouches:2];
        [pan setMaximumNumberOfTouches:2];

    }else{
        [pan setMinimumNumberOfTouches:1];
        [pan setMaximumNumberOfTouches:1];
    }
    [pan setDelegate:self];
    [self.view addGestureRecognizer:pan];



    [self.myView addGestureRecognizer:pan];
}


-(void)handlePan:(UIPanGestureRecognizer *)recognizer
{
    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];

    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;
        NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);

        float slideFactor = 0.1 * slideMult; // Increase for more of a slide
        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 animations:^{
            recognizer.view.center = finalPoint;
        } completion:nil];

    }
}

@end

/////更新

我不确定 [[UIApplication sharedApplication] reloadInputViews]; 如何调用函数来更新代码中的 UIPanGestureRecongizer,但我尝试通过 setupView 方法尽可能重新创建您的功能每次我点击 UISwitch
时调用 我创建了一个带有 UIPanGestureReconginzer 的自定义视图,以及一个我从 UIViewController 调用的方法来更新 setNumberOfTouches。该视图按预期工作。这里的关键不是初始化一个新的 UIPanGuestureRecongizer 而是更新现有的 UIPanGuestureRecongizer 。我假设在您的应用 UIViewControllerUIView 中没有完全重新加载 UIPanGuestureRecongizer
我创建了一个 属性 UIPanGuestureRecongizer ,它在第一次被访问时被初始化,然后在按下开关时被更新。这是自定义 UIView 代码。如果您对代码有任何疑问,请告诉我。

#import "MyTestView.h"
@interface MyTestView() <UIGestureRecognizerDelegate>


@property(nonatomic,strong) UIPanGestureRecognizer *panGesture;
@end


@implementation MyTestView



-(instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setupView];
    }
    return self;
}



-(UIPanGestureRecognizer *)panGesture
{
    //lazy instantiation

    if (!_panGesture) {
        _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    }

    return _panGesture;
}

-(void)setupView
{
    //this gets called everytime the UISwitch is being pressed.

    NSLog(@"Setup views");

    self.backgroundColor = [UIColor redColor];


    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    BOOL switchOn = [userDefaults boolForKey:@"SwipeNav"];

    if (switchOn) {
        // 2 Finger SwipeNav
        [self.panGesture setMinimumNumberOfTouches:2];
        [self.panGesture setMaximumNumberOfTouches:2];

    }else{
        [self.panGesture setMinimumNumberOfTouches:1];
        [self.panGesture setMaximumNumberOfTouches:1];
    }
    [self.panGesture setDelegate:self];
    [self addGestureRecognizer:self.panGesture];



}


-(void)handlePan:(UIPanGestureRecognizer *)recognizer
{
    CGPoint translation = [recognizer translationInView:self];
    recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
                                         recognizer.view.center.y + translation.y);
    [recognizer setTranslation:CGPointMake(0, 0) inView:self];

    if (recognizer.state == UIGestureRecognizerStateEnded) {

        CGPoint velocity = [recognizer velocityInView:self];
        CGFloat magnitude = sqrtf((velocity.x * velocity.x) + (velocity.y * velocity.y));
        CGFloat slideMult = magnitude / 200;
        NSLog(@"magnitude: %f, slideMult: %f", magnitude, slideMult);

        float slideFactor = 0.1 * slideMult; // Increase for more of a slide
        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.bounds.size.width);
        finalPoint.y = MIN(MAX(finalPoint.y, 0), self.bounds.size.height);

        [UIView animateWithDuration:slideFactor*2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
            recognizer.view.center = finalPoint;
        } completion:nil];

    }
}


@end

好吧,经过多次testing/code翻转,我想我找到了我的解决方案。

那么多一点背景故事,我使用MMDrawerController,所以上面关于放置[self setupView]的方法;在 (instancetype)initWithCoder 中没有做任何事情。 setupView 或在我的例子中称为 "setupGestureRecognizers" 被加载到 viewDidLoad 中。在其他任何地方它都不会加载手势。

使用我当前的开关代码和手势加载,我有这个:

    -(UIPanGestureRecognizer *)panGestureNav {

    if (!_panGesture) {
        _panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureCallback:)];
    }

    return _panGesture;
}

-(void)setupGestureRecognizers{

    switchOn = [[NSUserDefaults standardUserDefaults] boolForKey:@"SwipeNav"];

    if (switchOn == YES) {
        // 2 Finger SwipeNav
        [self.panGestureNav setMinimumNumberOfTouches:2];
        [self.panGestureNav setMaximumNumberOfTouches:2];
        NSLog(@"2 Finger Nav");

    }else {
        [self.panGestureNav setMinimumNumberOfTouches:1];
        [self.panGestureNav setMaximumNumberOfTouches:1];
        NSLog(@"Normal Nav");
    }
    [self.panGestureNav setDelegate:self];
    [self.view addGestureRecognizer:self.panGestureNav];

    UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureCallback:)];
    [tap setDelegate:self];
    [self.view addGestureRecognizer:tap];

}

这通常可以正常工作,但这个库做事不同,所以我必须研究他们的手势调用,我最终做的是在这里调用它:

-(MMOpenDrawerGestureMode)possibleOpenGestureModesForGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer withTouch:(UITouch*)touch{
    CGPoint point = [touch locationInView:self.childControllerContainerView];
    MMOpenDrawerGestureMode possibleOpenGestureModes = MMOpenDrawerGestureModeNone;
    if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]){

        [self setupGestureRecognizers]; <------------

所以现在它可以按我想要的方式加载和运行。

谢谢闫老师的帮助。希望这对某人有所帮助。