我正在尝试为UIPageViewController禁用平移手势识别器。
在iOS 5上,我可以遍历它们并禁用它们。
for (UIGestureRecognizer* recognizer in self.pageViewController.gestureRecognizers) {
if ([recognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
recognizer.enabled = NO;
}
}
在使用UIPageViewControllerTransitionStyleScroll的iOS 6上,页面视图控制器没有返回任何手势识别器。
这可归结为:
当UIPageViewController的过渡样式设置为滚动时,self.pageViewController.gestureRecognizers = 0,因此我无法访问手势识别器。
有什么方法可以解决这个问题吗?我不认为我做错了什么,因为卷曲过渡工作正常。
答案 0 :(得分:31)
在UIPageViewController.h中找到它:
//仅在转换样式为'UIPageViewControllerTransitionStylePageCurl'时才填充。 @property(非原子,只读)NSArray * gestureRecognizers;
所以,不是错误 - 按设计,当设置滚动样式时,pageViewController不会获得手势识别器。
答案 1 :(得分:27)
您始终可以尝试在页面视图控制器的子视图中禁用用户交互:
for (UIScrollView *view in self.pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
view.scrollEnabled = NO;
}
}
答案 2 :(得分:25)
此行为有bug filed in radar。所以,我敢打赌,在Apple修复之前,没有机会解决这个问题。
我想到的一个解决方法是在UIPageViewController
的顶部放置一个透明的子视图,并添加UIPanGestureRecognizer
来拦截这种姿势,而不是进一步前进。您可以在需要禁用手势时启用此视图/识别器。
我尝试使用Pan和Tap手势识别器的组合,它可以工作。
这是我的测试代码:
- (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
中的一个看似错误(至少,实际行为与参考状态明显不同),我看不出更好的解决方案。
答案 3 :(得分:18)
根据UIPageViewController头文件,当数据源为nil时,禁用手势驱动导航。
因此,如果要禁用滑动,请将datasource设置为nil,然后当您要启用滑动时,请重置数据源。
即
// turns off paging
pageViewController.datasource = nil
// turns on paging
pageViewController.datasource = self;
答案 4 :(得分:8)
您可以从UIPageViewController通过UIScrollview访问UIPanGestureRecognizer。
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:)];
}
}
答案 5 :(得分:2)
如果UIPageViewControllers UIPanGestureRecognizer正在进食/吞咽远离其他PanGestureRecognizer的所有事件(例如滑动菜单)。
您可以轻松扩展Bernies解决方案并使UIScrollViews PanGestureRecognizer要求其他识别器失败。 像这样:
for (UIView *view in pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]){
UIScrollView *scrollView = (UIScrollView *)view;
[scrollView.panGestureRecognizer requireGestureRecognizerToFail:otherRecognizer];
}
}
这样滚动的PanGestureRecognizer只会在我打算进入的区域触发。
这可能不是最好的未来证明解决方案,因为我们要求Apple不要更改UIPcViewView控制器内部使用UIScrollView。但...
答案 6 :(得分:1)
假设您可以找到手势识别器并将其移除是非常脆弱的。您正在使用Apple的假设知识实现UIPageViewController如何在您的应用程序中提供功能。如果这种情况发生变化(例如在iOS 5和iOS 6之间),那么您的代码应用程序将开始以意想不到的方式运行。这几乎就像使用私有API一样 - 您无法保证它将适用于下一个操作系统版本。
答案 7 :(得分:1)
如果使用KVC(键值编码)方法访问识别器会发生什么? (我现在不是我可以测试它的地方。)
快速测试可能是检索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,而是空的。但有趣的是,视图也没有放弃它的识别器 - 虽然滚动功能在那里,所以它必须至少有一个泛识别器......
答案 8 :(得分:0)
另一种解决方案,仅限历史。 你可以使任何视图成为一些手势识别器断路器,它应该在该视图的矩形中工作。必须有另一个UIPanGestureRecognizer与委托。它可以是一种方法的任何对象:
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
这可以作为单身人士使用:
static GestureRecognizerBreaker* PageViewControllerLocker() {
static GestureRecognizerBreaker* i = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
i = [[GestureRecognizerBreaker alloc]
initWithBreakerClass:UIPanGestureRecognizer.class
checker:^BOOL(UIGestureRecognizer* recognizer) {
UIView* v = recognizer.view;
UIResponder* r = v.nextResponder;
while (r) {
if ([r isKindOfClass:UIPageViewController.class])
return YES;
r = r.nextResponder;
}
return NO;
}];
});
return i;
}
调用-lockForView后:页面控制器的手势在视图框架中拖动时不起作用。例如,我想锁定视图控制器的整个空间。所以在视图控制器方法的某个时刻我调用
[PageViewControllerLocker() lockForView:self.view];
另一点
[PageViewControllerLocker() unlockForView:self.view];
答案 9 :(得分:0)
在pageviewcontroller内部有一个名为quieingscrollview的子视图,它有3个手势识别器,用于控制页面视图控制器 让他们使用
[[pageViewController.view.subviews objectAtIndex:0] gestureRecognizers]
答案 10 :(得分:0)
在我的情况下,我有一个UIView“信息面板”,它来自我的UIPageViewController,但页面视图控制器的手势识别器干扰了我的信息面板导航。
我的解决方案是将dataSource设置为nil,但也不允许页面视图控制器在信息面板启动时更新焦点:
- (BOOL)shouldUpdateFocusInContext:(UIFocusUpdateContext *)context
{
if (self.infoPanel) {
return NO;
} else {
return YES;
}
}
答案 11 :(得分:-1)
您可以使用UIGestureRecognizer
的委托方法来捕获和禁用任何手势例如,您可以使用此委托回调:gestureRecognizer:shouldReceiveTouch:
。只需确保为所有识别器设置委托。