【问题标题】:UIButton interaction inside UIPageViewControllerUIPageViewController 内部的 UIButton 交互
【发布时间】:2011-11-07 13:58:59
【问题描述】:
我在我的应用程序中使用了一个 UIPageViewController,我想在其中有一些 UIButtons,有点像菜单。我遇到的问题是,当我将 UIButton(或任何其他交互式元素)放在屏幕边缘附近并点击它时,而不是应用 UIButton 操作,会发生页面更改(因为点击边缘屏幕更改 UIPageViewController 上的页面)。我想知道是否有办法让 UIButton 具有比 UIPageViewController 更高的优先级,这样当我点击按钮时,它会应用适当的操作而不是更改页面。
【问题讨论】:
标签:
iphone
objective-c
xcode
uipageviewcontroller
【解决方案1】:
我带着同样的问题来到这里。斯普利特的link 给出了答案。
让您的根视图控制器成为每个UIPageViewController 的手势识别器的代表,然后防止触摸发生在任何UIControl 内:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
return ([touch.view isKindOfClass:[UIControl class]] == NO);
}
【解决方案2】:
UIPageViewController 有两个 UIGestureRecognizers。您可以通过 gestureRecognizers 属性访问它们。确定哪个是 UITapGestureRecognizer 然后使用 this. 希望这会有所帮助。
【解决方案3】:
对于只想复制/粘贴代码的人,这是我的:
// I don't want the tap on borders to change the page
-(void) desactivatePageChangerGesture {
for (UIGestureRecognizer* gestureRecognizer in self.pageViewController.gestureRecognizers) {
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
gestureRecognizer.enabled = NO;
}
}
}
在 UIPageViewController 创建后调用这个函数。
【解决方案4】:
我遇到了同样的问题,不确定如何处理 UIGestureRecognizer 委托方法。这个简短的示例假设您在 Xcode 4 中使用“基于页面的应用程序”项目类型。这是我所做的:
-
在RootViewController.h 中,我确保宣布 RootViewController 将处理 UIGestureRecognizerDelegate 协议:
@interface RootViewController : UIViewController <UIPageViewControllerDelegate, UIGestureRecognizerDelegate>
-
在RootViewController.m 中,我将 RootViewController 指定为 UITapGestureRecognizer 的委托。这是在viewDidLoad 方法的末尾完成的。我通过遍历每个gestureRecognizer 来查看哪个是UITapGestureRecognizer。
NSEnumerator *gestureLoop = [self.view.gestureRecognizers objectEnumerator];
id gestureRecognizer;
while (gestureRecognizer = [gestureLoop nextObject]) {
if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
[(UITapGestureRecognizer *)gestureRecognizer setDelegate:self];
}
}
-
最后,我在RootViewController.m的底部添加了gestureRecognizer:shouldReceiveTouch方法(这是直接从Split的链接复制而来的):
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIControl class]]) {
// we touched a button, slider, or other UIControl
return NO; // ignore the touch
}
return YES; // handle the touch
}
【解决方案5】:
从您的代码中注释掉这些行
self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;
或者按照 Split 的说明使用 UIGestureRecognizer
希望对你有帮助
【解决方案6】:
旧答案:如果您的UIPageViewController 有transitionStyle 或UIPageViewControllerTransitionStyleScroll,并且您使用的是iOS 6.0+,那么您不能使用gestureRecognizer:shouldReceiveTouch: 方法,因为有无法在gestureRecognizers 上将代理设置为self,因为pageViewController.gestureRecognizers 将返回nil。有关详细信息,请参阅UIPageViewController returns no Gesture Recognizers in iOS 6。
如果您只是想确保您的 UIPageViewController 将按钮触摸事件传递给 UIButton,您可以使用
for (UIScrollView *view in _pageViewController.view.subviews) {
if ([view isKindOfClass:[UIScrollView class]]) {
view.delaysContentTouches = NO;
}
}
如果您有 transitionStyle 或 UIPageViewControllerTransitionStyleScroll 并且您使用的是 iOS 6.0+。
请参阅this answer,了解为什么 UIButton 在 UIScrollView 中的某些情况下需要 delaysContentTouches = NO
更新:在做了更多研究之后,如果您的问题是 UIButton 点击似乎只被称为有时,那么这实际上可能是UIScrollView 中的所需行为。 UIScrollView 使用 delaysContentTouches 属性自动确定用户是在尝试滚动还是尝试在滚动视图中按下按钮。我认为最好不要将此行为更改为默认为NO,因为如果用户的手指放在按钮上,这样做会导致无法滚动。
【解决方案7】:
此处截取 UIPageViewController 的点击手势识别器的解决方案均不适合我。我的目标是 iOS 8 和 9。
有效的是在我的自定义按钮(UIControl 的子类)中覆盖函数touchesBegan、touchesCancelled、touchesMoved 和touchesEnded。然后,如果触摸在我的自定义按钮的框架内开始和结束,我只需手动发送.TouchUpInside 控制事件。
我不必为包含页面视图控制器或包含页面视图控制器的视图控制器做任何特别的事情。
【解决方案8】:
这里的 Swift 5 答案应该可以完成这项工作。
pageViewController.view.subviews.compactMap({ $0 as? UIScrollView }).first?.delaysContentTouches = false