I created a new project and tried to reproduce the problem that you are seeing and everything seems to work as expected. When switch is on the you need two buttons to pan and when switch is off you only need one. Let me know if that points you in the right direction. Your code seems to be correct.
I copy pasted the handlePan function from How to use UIPanGestureRecognizer to move object? iPhone/iPad
Created everything programmatically and copy pasted your code to save the state of the switch. Here is the code from two UIViewControllers
//
// ViewController.m
// StackOverflowSwitch
//
//
//
//
#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
///// Update
I am not exactly sure how [[UIApplication sharedApplication] reloadInputViews];
calls the function to update the UIPanGestureRecongizer
in your code but i tried to recreate your functionality as close as possible by having the setupView
method called every time i click the UISwitch
I created a custom view with UIPanGestureReconginzer
in there and a method that I call from the UIViewController to update setNumberOfTouches
. The view works as expected. The key here is not to initialize a new UIPanGuestureRecongizer
but update the existing one. I assume in your app UIViewController
or UIView
which has the UIPanGuestureRecongizer
is not being fully reloaded.
I created a property UIPanGuestureRecongizer
which gets initialized the first time it's being accessed and then gets updated when switch is being pressed. Here is the custom UIView code. Let me know if you have any questions regarding the code.
#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