xcode UIPageViewController 中的 UIButton 交互

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8037448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 22:21:03  来源:igfitidea点击:

UIButton interaction inside UIPageViewController

iphoneobjective-cxcodeuipageviewcontroller

提问by gutenbergn

I'm using an UIPageViewController in my application and I wanted to have a few UIButtons inside it, sort of like a menu. The problem I have is that when I put an UIButton (or any other interactive element) near the edges of the screen and tap it, instead of the UIButton action being applied, what happens is that the page changes (because the tap on the edge of the screen changes the page on the UIPageViewController). I'd like to know if there's a way to make it so that the UIButton has higher priority than the UIPageViewController so that when I tap the button, it applies the appropriate action instead of changing the page.

我在我的应用程序中使用了 UIPageViewController,我想在其中包含一些 UIButton,有点像菜单。我遇到的问题是,当我在屏幕边缘附近放置一个 UIButton(或任何其他交互元素)并点击它时,而不是应用 UIButton 操作,会发生页面更改(因为点击边缘屏幕更改 UIPageViewController 上的页面)。我想知道是否有办法使 UIButton 具有比 UIPageViewController 更高的优先级,这样当我点击按钮时,它会应用适当的操作而不是更改页面。

采纳答案by Ryder Mackay

I came here with the same problem. Split's linkhas the answer.

我带着同样的问题来到这里。Split 的链接给出了答案。

Make your root view controller the delegate of each of the UIPageViewController's gesture recognizers, then prevent touches from being delivered if they occur inside any UIControl:

使您的根视图控制器成为每个UIPageViewController手势识别器的代理,然后防止在 any 内发生触摸时传递触摸UIControl

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
    return ([touch.view isKindOfClass:[UIControl class]] == NO);
}

回答by Split

UIPageViewController has two UIGestureRecognizers. You can access them via gestureRecognizers property. Determine which one is UITapGestureRecognizer and then use this.Hope this helps.

UIPageViewController 有两个 UIGestureRecognizers。您可以通过gestureRecognizers 属性访问它们。确定哪个是 UITapGestureRecognizer 然后使用它。希望这可以帮助。

回答by CedricSoubrie

For people that just want to copy/paste code, here is mine :

对于只想复制/粘贴代码的人,这是我的:

// 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;
        }
    }
}

Just call this function after the UIPageViewController creation.

只需在 UIPageViewController 创建后调用此函数即可。

回答by Soniya

Comment out these line from your code

从您的代码中注释掉这些行

self.view.gestureRecognizers = self.pageViewController.gestureRecognizers;

or use UIGestureRecognizer as told by Split

或者使用 Split 所说的 UIGestureRecognizer

Hope this will help you

希望能帮到你

回答by Nate Smith

I had this same problem, and was unsure how to handle the UIGestureRecognizer delegate methods. This short example assumes you are using the "Page Based Application" project type in Xcode 4. Here is what I did:

我遇到了同样的问题,并且不确定如何处理 UIGestureRecognizer 委托方法。这个简短的示例假设您在 Xcode 4 中使用“基于页面的应用程序”项目类型。这是我所做的:

  • In RootViewController.h, I made sure to announce that RootViewController would handle the UIGestureRecognizerDelegate protocol:

    @interface RootViewController : UIViewController <UIPageViewControllerDelegate, UIGestureRecognizerDelegate>
    
  • In RootViewController.m, I assigned RootViewController as the delegate for the UITapGestureRecognizer. This is done at the end of the viewDidLoadmethod. I did this by iterating over each gestureRecognizer to see which one was the UITapGestureRecognizer.

    NSEnumerator *gestureLoop = [self.view.gestureRecognizers objectEnumerator];
    id gestureRecognizer;
    while (gestureRecognizer = [gestureLoop nextObject]) {
        if ([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
            [(UITapGestureRecognizer *)gestureRecognizer setDelegate:self];
        }
    }
    
  • Finally, I added the gestureRecognizer:shouldReceiveTouch method to the bottom of RootViewController.m(This is copied directly from Split's link):

    - (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
    }
    
  • 在 中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];
        }
    }
    
  • 最后,我在底部添加了gestureRecognizer:shouldReceiveTouch方法RootViewController.m(这是直接从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
    }
    

回答by Adam Johns

OLD ANSWER:If your UIPageViewControllerhas a transitionStyleof UIPageViewControllerTransitionStyleScrolland you are in iOS 6.0+, then you can't use the gestureRecognizer:shouldReceiveTouch:method, because there is no way to set the delegate to selfon the gestureRecognizerssince pageViewController.gestureRecognizerswill return nil. See UIPageViewController returns no Gesture Recognizers in iOS 6for more information about that.

旧答案:如果你UIPageViewController有一个transitionStyleofUIPageViewControllerTransitionStyleScroll并且你在 iOS 6.0+ 中,那么你不能使用该gestureRecognizer:shouldReceiveTouch:方法,因为没有办法将委托设置为selfongestureRecognizers因为pageViewController.gestureRecognizers将返回 nil。有关更多信息,请参阅UIPageViewController 在 iOS 6 中不返回手势识别器

If you simply want to make sure your UIPageViewControllerpasses along button touch events to a UIButton, you can use

如果您只是想确保UIPageViewController将按钮触摸事件传递给 UIButton,则可以使用

for (UIScrollView *view in _pageViewController.view.subviews) {
    if ([view isKindOfClass:[UIScrollView class]]) {
        view.delaysContentTouches = NO;
    }
}

if you have a transitionStyleof UIPageViewControllerTransitionStyleScrolland you are in iOS 6.0+.

如果你有一个transitionStyleUIPageViewControllerTransitionStyleScroll,你在iOS 6.0以上版本。

See this answerabout why delaysContentTouches = NOis needed for some cases of a UIButtonin a UIScrollView

请参阅有关为什么在某些情况下需要 a in a 的答案delaysContentTouches = NOUIButtonUIScrollView

UPDATE:After doing a little more research it appears that if your issue is that the UIButtonclick seems to only be called sometimes, then that is actually probably the desired behavior inside a UIScrollView. A UIScrollViewuses the delaysContentTouchesproperty to automatically determine if the user was trying to scroll or trying to press a button inside the scroll view. I would assume it is best to not alter this behavior to default to NOsince doing so will result in an inability to scroll if the user's finger is over a button.

更新:在进行更多研究之后,似乎如果您的问题是UIButton单击似乎只是有时被调用,那么这实际上可能是UIScrollView. AUIScrollView使用delaysContentTouches属性来自动确定用户是尝试滚动还是尝试按下滚动视图内的按钮。我认为最好不要将此行为更改为默认值,NO因为如果用户的手指在按钮上,这样做将导致无法滚动。

回答by Matthew Quiros

None of the solutions here where you intercept the UIPageViewController's tap gesture recognizers worked for me. I'm targeting iOS 8 and 9.

此处拦截 UIPageViewController 的点击手势识别器的解决方案都不适用于我。我的目标是 iOS 8 和 9。

What worked is to override the functions touchesBegan, touchesCancelled, touchesMoved, and touchesEndedin my custom button which is a subclass of UIControl. Then I just manually send the .TouchUpInsidecontrol event if the touch began and ended within the frame of my custom button.

有效的方法是覆盖我的自定义按钮中的函数touchesBegantouchesCancelledtouchesMovedtouchesEnded,它是UIControl. 然后,.TouchUpInside如果触摸在我的自定义按钮的框架内开始和结束,我只需手动发送控制事件。

I didn't have to do anything special for the containing page view controller, or the view controller that contains the page view controller.

我不必为包含页面视图控制器或包含页面视图控制器的视图控制器做任何特别的事情。

回答by SparkyRobinson

Swift 5 answer here should do the job.

Swift 5 answer here 应该可以完成这项工作。

pageViewController.view.subviews.compactMap({ $0 as? UIScrollView }).first?.delaysContentTouches = false

pageViewController.view.subviews.compactMap({ $0 as? UIScrollView }).first?.delaysContentTouches = false