Iphone UIPageViewController在iOS 6中不返回任何手势识别器
我正在尝试禁用UIPageViewController的平移手势识别器 在iOS 5上,我可以循环并禁用它们Iphone UIPageViewController在iOS 6中不返回任何手势识别器,iphone,objective-c,uikit,uipageviewcontroller,Iphone,Objective C,Uikit,Uipageviewcontroller,我正在尝试禁用UIPageViewController的平移手势识别器 在iOS 5上,我可以循环并禁用它们 for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) { if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) { recognizer.enabled = NO; } }
for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
在使用UIPageViewControllerTransitionStyleScroll的iOS 6上,页面视图控制器没有返回任何手势识别器
澄清
这可以归结为:
当UIPageViewController的转换样式设置为滚动,因此我无法访问手势识别器时,self.pageViewController.GestureRecograiners=0
我有什么办法可以绕开这件事吗?我不认为我做错了什么,因为curl转换工作正常。您可以使用
uigestureerecognizer
的委托方法捕获并禁用任何手势。例如,您可以使用此委托回调:gestureerecognizer:shouldReceiveTouch:
。只需确保为所有识别器设置委托即可。此行为有一个有效的解决方案。所以,我打赌,在苹果修复之前,没有机会解决这个问题
我想到的一个解决方法是在UIPageViewController
的顶部放置一个透明的子视图,并在其上添加一个uipangestrerecognizer
,以截取这种手势,而不是向前移动。当需要禁用手势时,可以启用此视图/识别器
我用平移和轻拍手势识别器的组合进行了尝试,效果很好
这是我的测试代码:
- (void)viewDidLoad {
[super viewDidLoad];
UIPanGestureRecognizer* g1 = [[[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(g1Pan:)] autorelease];
[self.view addGestureRecognizer:g1];
UITapGestureRecognizer* s1 = [[[UITapGestureRecognizer alloc] initWithTarget:self
action:@selector(g1Tap:)] autorelease];
[self.view addGestureRecognizer:s1];
UIView* anotherView = [[[UIView alloc]initWithFrame:self.view.bounds] autorelease];
[self.view addSubview:anotherView];
UIPanGestureRecognizer* g2 = [[[UIPanGestureRecognizer alloc] initWithTarget:self
action:@selector(g2Pan:)] autorelease];
[anotherView addGestureRecognizer:g2];
}
启用g2
时,将阻止识别g1
。另一方面,它不会阻止s1被识别
我理解这是一种黑客行为,但面对
UIPageViewController
中看似存在的错误(至少,实际行为与参考状态明显不同),我看不到任何更好的解决方案。假设您可以找到手势识别器并将其删除,这是非常脆弱的。您正在使用苹果如何使用UIPageViewController在应用程序中提供功能的假定知识。如果这种情况发生变化(例如在iOS 5和iOS 6之间),则您的代码应用程序将开始以意外的方式运行。这几乎就像使用私有API—您无法保证它能在下一个操作系统版本中使用。如果您使用KVC(键值编码)方法访问识别器,会发生什么?(我现在不在可以测试的地方。)
快速测试可能是检索手势识别器的数量:
[self.pageViewController countOfKey:@"gestureRecognizers"];
NSArray *recognizers = [self.pageViewController
mutableArrayValueForKey:@"gestureRecognizers"];
如果有效,您可以进一步检索识别器阵列:
[self.pageViewController countOfKey:@"gestureRecognizers"];
NSArray *recognizers = [self.pageViewController
mutableArrayValueForKey:@"gestureRecognizers"];
瘦,但也许
编辑:最终能够进行测试。使用了以下内容:
NSArray *pvcGRsNoKVC = [[NSArray alloc]
initWithArray:self.pageViewController.gestureRecognizers];
NSArray *viewGRsNoKVC = [[NSArray alloc] initWithArray:self.view.gestureRecognizers];
NSArray *pvcGRsKVC = [[NSArray alloc]
initWithArray:[self.pageViewController valueForKey:@"gestureRecognizers"]];
NSArray *viewGRsKVC = [[NSArray alloc]
initWithArray:[self.view valueForKey:@"gestureRecognizers"]];
这没什么区别。卷曲的风格在两方面都很好;滚动样式显示的数组不是nil,而是空的。不过,有趣的是,视图也没有放弃其识别器-尽管有滚动功能,因此它必须至少有一个平移识别器…在UIPageViewController中找到了这一点。h: //仅当转换样式为“UIPageViewControllerTransitionStylePageCurl”时才填充。 @属性(非原子、只读)NSArray*手势识别器
因此,这不是一个bug-根据设计,当设置滚动样式时,pageViewController不会获得手势识别器。您始终可以尝试禁用页面视图控制器子视图上的用户交互:
for (UIScrollView *view in self.pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
view.scrollEnabled = NO;
}
}
您可以从UIPageViewController通过UIScrollview访问UIPangestureRecognitor
for (UIView *view in self.pageController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]])
{
UIScrollView *scrollView = (UIScrollView *)view;
UIPanGestureRecognizer* panGestureRecognizer = scrollView.panGestureRecognizer;
[panGestureRecognizer addTarget:self action:@selector(move:)];
}
}
另一个解决方案,只是为了历史。 您可以使任何视图成为某个手势识别器断路器,它应该在该视图的矩形中工作。必须有另一个具有委托的UIPangestureRecognitor。它可以是具有一种方法的任何对象:
static UIPageViewController* getPageViewControllerFromView(UIView* v) {
UIResponder* r = v.nextResponder;
while (r) {
if ([r isKindOfClass:UIPageViewController.class])
return (UIPageViewController*)r;
r = r.nextResponder;
}
return nil;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
if (getPageViewControllerFromView(otherGestureRecognizer.view))
{
otherGestureRecognizer.enabled = NO;
otherGestureRecognizer.enabled = YES;
}
return NO;
}
您可以使用以下类来中断识别器:
@interface GestureRecognizerBreaker : NSObject <UIGestureRecognizerDelegate>
{
UIGestureRecognizer* breaker_;
BOOL(^needsBreak_)(UIGestureRecognizer*);
}
- (id) initWithBreakerClass:(Class)recognizerClass
checker:(BOOL(^)(UIGestureRecognizer* recognizer))needsBreak;
- (void) lockForView:(UIView*)view;
- (void) unlockForView:(UIView*)view;
@end
@implementation GestureRecognizerBreaker
- (void) dummy:(id)r {}
- (id) initWithBreakerClass:(Class)recognizerClass checker:(BOOL(^)(UIGestureRecognizer*))needsBreak {
self = [super init];
if (!self)
return nil;
NSParameterAssert([recognizerClass isSubclassOfClass:UIGestureRecognizer.class] && needsBreak);
needsBreak_ = needsBreak;
breaker_ = [[recognizerClass alloc] initWithTarget:self action:@selector(dummy:)];
breaker_.delegate = self;
return self;
}
- (BOOL) gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
if (needsBreak_(otherGestureRecognizer)) {
otherGestureRecognizer.enabled = NO;
otherGestureRecognizer.enabled = YES;
}
return NO;
}
- (void) lockForView:(UIView*)view {
[view addGestureRecognizer:breaker_];
}
- (void) unlockForView:(UIView*)view {
[view removeGestureRecognizer:breaker_];
}
@end
调用-lockForView后:页面控制器的手势无法在视图的框架中拖动。例如,我想锁定视图控制器的整个空间。所以从某个角度来看,我调用
[PageViewControllerLocker() lockForView:self.view];
另一方面
[PageViewControllerLocker() unlockForView:self.view];
根据UIPageViewController头文件,当数据源为nil时,将禁用手势驱动的导航 因此,当您想要禁用刷卡时,将datasource设置为nil,然后当您想要启用刷卡时,重置数据源 i、 e
如果UIPageViewControllers UIPangEstureRecognitor正在从其他PangEstureRecognitor(如滑动菜单)读取/吞咽所有事件 您可以轻松地扩展Bernies解决方案,并使UIScrollViews PangestureRecognitor要求另一个识别器失败。 大概是这样的:
for (UIView *view in pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]){
UIScrollView *scrollView = (UIScrollView *)view;
[scrollView.panGestureRecognizer requireGestureRecognizerToFail:otherRecognizer];
}
}
这样滚动的PangestureRecognitor只会在我想要它的区域开火
这可能不是最好的未来证明解决方案,因为我们要求苹果不改变UIScrollView的UIPageViewController内部使用。但是…在pageviewcontroller内部有一个名为quieingscrollview的子视图,它有3个手势识别器,用于控制PageView控制器 让他们使用
[[pageViewController.view.subviews objectAtIndex:0] gestureRecognizers]
在我的例子中,我的UIPageViewController上有一个UIView“信息面板”,但是页面视图控制器的手势识别器干扰了通过我的信息面板的导航 我的解决方案是将数据源设置为nil,但也不允许页面视图控制器在信息面板打开时更新焦点:
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
{
if (self.infoPanel) {
return NO;
} else {
return YES;
}
}
问题不是禁用手势识别器不起作用,而是我无法访问手势识别器,因为它们不是从带有滚动转换样式的UIPageViewController返回的。我发现了完全相同的问题。可能iOS6没有在UIPageVC上使用UIPangestureRecognitor。您是否尝试过插入自己的手势识别器,并以某种方式强制其超越默认的滑动/平移行为?如果您的转换样式设置为UIPageViewControllerTransitionStylePageCurl,则此功能在iOS 6上仍然有效->此处更简单->捕捉良好。显然我应该