选择不同的 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
。我假设在您的应用 UIViewController
或 UIView
中没有完全重新加载 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]; <------------
所以现在它可以按我想要的方式加载和运行。
谢谢闫老师的帮助。希望这对某人有所帮助。
好的,我有一个带有左侧菜单和右侧视图控制器的应用程序,它们由 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
。我假设在您的应用 UIViewController
或 UIView
中没有完全重新加载 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]; <------------
所以现在它可以按我想要的方式加载和运行。
谢谢闫老师的帮助。希望这对某人有所帮助。