禁用 UIPageViewController 反弹

Posted

技术标签:

【中文标题】禁用 UIPageViewController 反弹【英文标题】:Disable UIPageViewController bounce 【发布时间】:2014-02-15 13:30:36 【问题描述】:

为此搜索了很多,但还没有找到合适的解决方案。

是否可以禁用UIPageViewController 的反弹效果并仍然使用UIPageViewControllerTransitionStyleScroll

【问题讨论】:

如果你想移除弹跳,你可以使用 UIPageViewControllerTransitionStylePageCurl 样式。 @pawan 我想使用 UIPageViewControllerTransitionStyleScroll 【参考方案1】:

禁用 UIPageViewController 的反弹

    <UIScrollViewDelegate> 委托添加到 UIPageViewController 的标题

    将 UIPageViewController 的底层 UIScrollView 的委托设置为 viewDidLoad 中的父代:

    for (UIView *view in self.view.subviews) 
        if ([view isKindOfClass:[UIScrollView class]]) 
            ((UIScrollView *)view).delegate = self;
            break;
        
    
    

    scrollViewDidScroll 的实现是在用户超出范围,如下所示:

    - (void)scrollViewDidScroll:(UIScrollView *)scrollView 
        if (_currentPage == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width) 
            scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
         else if (_currentPage == totalViewControllersInPageController-1 && scrollView.contentOffset.x > scrollView.bounds.size.width) 
            scrollView.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
        
    
    

    最后,scrollViewWillEndDragging的实现是为了处理用户在第一页从左向右快速滑动,第一页不会向左弹跳的bug场景(由于上面的函数),但会因(可能)滑动速度而在右侧反弹。最后,当反弹回来时,UIPageViewController 会触发翻页到第二页(这当然不是预期的)。

    - (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset 
        if (_currentPage == 0 && scrollView.contentOffset.x <= scrollView.bounds.size.width) 
            *targetContentOffset = CGPointMake(scrollView.bounds.size.width, 0);
         else if (_currentPage == totalViewControllersInPageController-1 && scrollView.contentOffset.x >= scrollView.bounds.size.width) 
            *targetContentOffset = CGPointMake(scrollView.bounds.size.width, 0);
        
    
    

斯威夫特 4.0

要放入viewDidLoad的代码:

for subview in self.view.subviews 
    if let scrollView = subview as? UIScrollView 
        scrollView.delegate = self
        break;
    

scrollViewDidScroll的实现:

func scrollViewDidScroll(_ scrollView: UIScrollView) 
    if (currentPage == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width) 
        scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0);
     else if (currentPage == totalViewControllersInPageController - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width) 
        scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0);
    

scrollViewWillEndDragging的实现:

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) 
    if (currentPage == 0 && scrollView.contentOffset.x <= scrollView.bounds.size.width) 
        targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0);
     else if (currentPage == totalViewControllersInPageController - 1 && scrollView.contentOffset.x >= scrollView.bounds.size.width) 
        targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0);
    

【讨论】:

我不明白这一行 *ta​​rgetContentOffset = CGPointMake(scrollView.bounds.size.width, 0);你能解释一下吗? @Andrespch UIPageViewController 的底层滚动视图会将 visible ViewController 的视图放置在偏移量:(scrollView.bounds.size.width, 0)。即前一个ViewController的view放在位置(0,0)~(scrollView.bounds.size.width,0),下一个ViewController的view放在位置(scrollView.bounds.size.width*2, 0)~( scrollView.bounds.size.width*3,0) 当用户滚动 UIPageViewController 以显示上一个和下一个视图时 @DongMa isPageToBounce_currentPage 应该是什么类型?我无法理解代码。你能逐步解释一下吗?我认为这是互联网上解决此问题的唯一方法(一直在寻找几个小时)。 谢谢 ;) 我试图解决这个问题太久了 :) 解决方案不完整,请补充说明如何跟踪当前页面。【参考方案2】:

禁用 UIPageViewController 的反弹

斯威夫特 2.2

Addition to answers

1) 将 UIScrollViewDelegate 添加到 UIPageViewController

extension PageViewController: UIScrollViewDelegate

2) 添加到 viewDidLoad

for view in self.view.subviews 
   if let scrollView = view as? UIScrollView 
      scrollView.delegate = self
   

3) 添加 UIScrollViewDelegate 方法

func scrollViewDidScroll(scrollView: UIScrollView) 
    if currentIndex == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width 
        scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
     else if currentIndex == totalViewControllers - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width 
        scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
    


func scrollViewWillEndDragging(scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) 
    if currentIndex == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width 
        scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
     else if currentIndex == totalViewControllers - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width 
        scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
    

【讨论】:

很好用,你只需要正确设置 currentIndex ! 一开始我不确定如何正确设置索引,最后做了我在答案中发布的内容,如果你想包含我可以删除 @BalázsPapp ,完全同意你的看法。 @BalázsPapp 你是如何正确设置 currentIndex 的? 查看这篇文章以在UIPageViewController***.com/questions/8400870/…中找到currentIndex【参考方案3】:

唯一可行的解​​决方案,2020 年

以下是一个完整的解决方案,与其他答案不同,它不需要您编写/测试自己的代码来跟踪当前显示页面的索引。

假设您的页面存储在sourcePageViewControllers 不可变数组中,并且在您将UIPageViewController 创建为myPageViewController 之后:

let scrollView = myPageViewController.view.subviews.compactMap( $0 as? UIScrollView ).first!
scrollView.delegate = <instance of YourScrollViewDelegateClass>

然后:

extension YourScrollViewDelegateClass: UIScrollViewDelegate 

    func scrollViewDidScroll(_ scrollView: UIScrollView) 
        guard sourcePageViewControllers.count > 1 else 
            scrollView.isScrollEnabled = false
            return
        
        
        guard let viewControllers = myPageViewController.viewControllers, viewControllers.count != 0 else  return 

        let baseRecord =
            viewControllers
            .map  [superview = myPageViewController.view!] viewController -> (viewController: UIViewController, originX: CGFloat) in
                let originX = superview.convert(viewController.view.bounds.origin, from: viewController.view).x
                return (viewController: viewController, originX: originX)
            
            .sorted(by:  $0.originX < $1.originX )
            .first!

        guard let baseIndex = sourcePageViewControllers.firstIndex(of: baseRecord.viewController) else  return 
        let baseViewControllerOffsetXRatio = -baseRecord.originX/scrollView.bounds.width

        let progress = (CGFloat(baseIndex) + baseViewControllerOffsetXRatio)/CGFloat(sourcePageViewControllers.count - 1)
        if !(0...1 ~= progress) 
            scrollView.isScrollEnabled = false
            scrollView.isScrollEnabled = true
        
    


【讨论】:

【参考方案4】:

如果您跟踪您的 currentIndex,那么以下内容应该就足够了,但它有点错误,因为有一个随机场景会完全停止滚动。

我认为 scrollView.bounces 有点错误,也许我遗漏了一些东西,因为大多数情况下它都可以正常工作,如果有人能够根据以下内容提供解决方案,那就太好了。

public func scrollViewDidScroll(_ scrollView: UIScrollView) 
    scrollView.bounces = currentIndex == 0 ||
        currentIndex == controllers.count - 1
        ? false 
        : true

【讨论】:

【参考方案5】:

我不确定如何正确管理currentIndex,但最终还是做了

extension Main: UIPageViewControllerDelegate 
    func pageViewController(pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
        if completed 
            guard let viewController = pageViewController.viewControllers?.first,
                index = viewControllerDatasource.indexOf(viewController) else 
                fatalError("Can't prevent bounce if there's not an index")
            
            currentIndex = index
        
    

【讨论】:

当前索引?问题是关于防止反弹 @ZaporozhchenkoAleksandr 如果不使用当前索引,您将无法防止反弹【参考方案6】:

另一个选项是设置 ScrollView.bounce = false。 它解决了我的 pageViewController(当然不是关于 ScrollView)滚动反弹的问题。 弹跳被禁用,所有页面都可以滚动而不会弹跳。

【讨论】:

这是错误的建议——如果 UIPageViewController 的滚动视图禁用了弹跳,它就会停止水平分页。【参考方案7】:

@Dong Ma 的方法很完美,但可以稍微改进和简化。

要放入 viewDidLoad 的代码:

for subview in view.subviews 
    if let scrollView = subview as? UIScrollView 
        scrollView.delegate = self
        break
    

scrollViewDidScroll的实现:

public func scrollViewDidScroll(_ scrollView: UIScrollView) 
    if (currentPage == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width) || (currentPage == totalNumberOfPages - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width) 
      scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
    
  

scrollViewWillEndDragging的实现:

public func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) 
    if (currentPage == 0 && scrollView.contentOffset.x <= scrollView.bounds.size.width) || (currentPage == totalNumberOfPages - 1 && scrollView.contentOffset.x >= scrollView.bounds.size.width) 
      targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
    
  

【讨论】:

【参考方案8】:

东马的编辑答案,其中:

添加 - 尊重布局方向(例如希伯来语) 已修复 - 快速滑动时错误计数 currentIndex

信息:

用 Swift 5.0 编写 在 Xcode 10.2.1 中构建和测试 ios 12.0

如何:

    假设我们有一个UIViewController,其中UIPageViewController 添加为子VC。
class ViewController: UIViewController 
    var pageNavigationController: UIPageViewController! 

    private var lastPosition: CGFloat
    private var nextIndex: Int
    var currentIndex: Int     

    // rest of UI's setups  

    ViewController设置为UIPageViewController的代表:
extension ViewController: UIPageViewControllerDataSource 

    func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) 
        guard
            let currentVisibleViewController = pageViewController.viewControllers?.first,
            let nextIndex = pageViewControllers.firstIndex(of: currentVisibleViewController)
        else 
            return
        

        self.nextIndex = nextIndex
    

    func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
        if completed, let currentVisibleViewController = pageViewController.viewControllers?.first, let newIndex = pageViewControllers.firstIndex(of: currentVisibleViewController) 
            self.currentIndex = newIndex
        

        self.nextIndex = self.currentIndex
    

    设置ViewControllerUIPageController的数据源:
extension ViewController: UIPageViewControllerDataSource 

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? 
        // provide next VC
    

    func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? 
        // provide prev VC
    

    // IMPORTANT: that's the key why it works, don't forget to add it
    func presentationIndex(for pageViewController: UIPageViewController) -> Int 
        return currentIndex
    

    通过将ViewController 设置为UIPageViewControllerUIScrollView 的代表来“禁用”弹跳:
// MARK: - UIScrollViewDelegate (disable bouncing for UIPageViewController)
extension BasePaginationVC: UIScrollViewDelegate 

    func attachScrollViewDelegate() 
        for subview in pageNavigationController.view.subviews 
            if let scrollView = subview as? UIScrollView 
                scrollView.delegate = self
                lastPosition = scrollView.contentOffset.x
                break
            
        
    

    func scrollViewDidScroll(_ scrollView: UIScrollView) 
        switch UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) 
        case .leftToRight:
            if nextIndex > currentIndex 
                if scrollView.contentOffset.x < (lastPosition - (0.9 * scrollView.bounds.size.width)) 
                    currentIndex = nextIndex
                
             else 
                if scrollView.contentOffset.x > (lastPosition + (0.9 * scrollView.bounds.size.width)) 
                    currentIndex = nextIndex
                
            

            if currentIndex == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width 
                scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
             else if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width 
                scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
            
        case .rightToLeft:
            if nextIndex > currentIndex 
                if scrollView.contentOffset.x > (lastPosition + (0.9 * scrollView.bounds.size.width)) 
                    currentIndex = nextIndex
                
             else 
                if scrollView.contentOffset.x < (lastPosition - (0.9 * scrollView.bounds.size.width)) 
                    currentIndex = nextIndex
                
            

            if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x < scrollView.bounds.size.width 
                scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
             else if currentIndex == 0 && scrollView.contentOffset.x > scrollView.bounds.size.width 
                scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0)
            
        @unknown default:
            fatalError("unknown default")
        

        lastPosition = scrollView.contentOffset.x
    

    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) 
        switch UIView.userInterfaceLayoutDirection(for: view.semanticContentAttribute) 
        case .leftToRight:
            if currentIndex == 0 && scrollView.contentOffset.x <= scrollView.bounds.size.width 
                targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
             else if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x >= scrollView.bounds.size.width 
                targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
            
        case .rightToLeft:
            if currentIndex == pageViewControllers.count - 1 && scrollView.contentOffset.x <= scrollView.bounds.size.width 
                targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
             else if currentIndex == 0 && scrollView.contentOffset.x >= scrollView.bounds.size.width 
                targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0)
            
        @unknown default:
            fatalError("unknown default")
        
    

【讨论】:

【参考方案9】:

我在 Swift 5 中的解决方案 在我的场景中,我首先在第二页加载UIPageViewController。我一共有三页,所以我打开中间的那一页。

这是我的UIPageViewController的代码

import UIKit

class MainPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, UIScrollViewDelegate 

  let idList = ["OverviewController", "ImportantItemsController", "ListMenuController"] // A list of all of my viewControllers' storyboard id
  var currentPage = 1 // Tracking the current page

  override func viewDidLoad() 
    super.viewDidLoad()
    setupPageController()

    for subview in self.view.subviews  // Getting the scrollView
      if let scrollView = subview as? UIScrollView 
        scrollView.delegate = self
        break;
      
    
  

  // UIPageViewControllerDataSource
  func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? 
    let index = idList.firstIndex(of: viewController.restorationIdentifier!)!
    if (index > 0) 
      return storyboard?.instantiateViewController(withIdentifier: idList[index - 1])
    
    return nil
  

  func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? 
    let index = idList.firstIndex(of: viewController.restorationIdentifier!)!
    if (index < idList.count - 1) 
      return storyboard?.instantiateViewController(withIdentifier: idList[index + 1])
    
    return nil
  

  func presentationCount(for pageViewController: UIPageViewController) -> Int 
    return idList.count
  

  // UIPageViewControllerDelegate
  func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) 
    if completed 
      guard let vc = pageViewController.viewControllers?.first else  return 
      switch vc 
      case is ImportantItemsController:
          currentPage = 1
      case is OverviewController:
          currentPage = 0
      default:
          currentPage = 2
      
    
  

  // ScrollViewDelegate
  func scrollViewDidScroll(_ scrollView: UIScrollView) 
    let totalViewControllersInPageController = idList.count
    if (currentPage == 0 && scrollView.contentOffset.x < scrollView.bounds.size.width) 
      scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0);
     else if (currentPage == totalViewControllersInPageController - 1 && scrollView.contentOffset.x > scrollView.bounds.size.width) 
      scrollView.contentOffset = CGPoint(x: scrollView.bounds.size.width, y: 0);
    
  

  func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) 
    let totalViewControllersInPageController = idList.count
    if (currentPage == 0 && scrollView.contentOffset.x <= scrollView.bounds.size.width) 
      targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0);
     else if (currentPage == totalViewControllersInPageController - 1 && scrollView.contentOffset.x >= scrollView.bounds.size.width) 
      targetContentOffset.pointee = CGPoint(x: scrollView.bounds.size.width, y: 0);
    
  

  fileprivate func setupPageController() 
    let controller = storyboard?.instantiateViewController(withIdentifier: idList[1]) as! ImportantItemsController // Loading on the second viewController
    setViewControllers([controller], direction: .forward, animated: true, completion: nil)
    dataSource = self
    delegate = self
  


【讨论】:

【参考方案10】:

如果您希望完全禁用 UIPageViewController 子类上的滚动视图,您可以使用下面的 sn-p。请注意,这不仅会禁用弹跳,还会禁用页面的水平滚动。

在我的情况下,我有一个 UISegmentedControl 在 PageViewController 中的页面之间切换,因此禁用垂直滚动完全没问题,并且对我有用。希望对其他人也有帮助。

class MyPageViewController: UIPageViewController 

    private lazy var scrollView: UIScrollView =  view.subviews.compactMap( $0 as? UIScrollView ).first! ()

    override func viewDidLoad() 
        super.viewDidLoad()

        scrollView.isScrollEnabled = false
    

【讨论】:

【参考方案11】:

UIPageViewController 实际上并没有为您做太多事情。您可以很容易地将 UIScrollView 与视图控制器一起使用,并在其上禁用反弹。

只是做一些类似的事情

int x=0;
for (NSString *storyboardID in storyboardIDs)
        UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:storyboardID];
        [self addChildViewController:vc];
        vc.view.frame = CGRectMake(x++*vc.view.frame.size.width, 0, vc.view.frame.size.width, vc.view.frame.size.height);
        [self.scrollView addSubview:vc.view];
        [vc didMoveToParentViewController:self];
        self.scrollView.contentSize = CGSizeMake(storyboardIDs.count*vc.view.frame.size.width, vc.view.frame.size.height);

【讨论】:

真的! UIPageViewController 使事情变得更加复杂,我能看到的基本用法的唯一优势是 Page Curl 效果的实现比 UIScrollView 更容易。并不是说它是大约 10 行代码,而页面控制器是 100 行:)【参考方案12】:

如果您尝试禁用UIPageViewController.scrollView 的弹跳,您肯定会得到一个损坏的pageViewController:滑动不起作用。所以,不要那样做:

self.theScrollView.alwaysBounceHorizontal = NO;
self.theScrollView.bounces = NO;

使用在UIPageViewController 子视图中搜索scrollView 引用的解决方案仅用于完全禁用滚动:

@interface MyPageViewController : UIPageViewController
@property (nonatomic, assign) BOOL scrollEnabled;
@end

@interface MyPageViewController ()
@property (nonatomic, weak) UIScrollView *theScrollView;
@end

@implementation MyPageViewController

- (void)viewDidLoad

    [super viewDidLoad];
    for (UIView *view in self.view.subviews) 
        if ([view isKindOfClass:UIScrollView.class]) 
            self.theScrollView = (UIScrollView *)view;
            break;
        
    


- (void)setScrollEnabled:(BOOL)scrollEnabled

    _scrollEnabled = scrollEnabled;
    self.theScrollView.scrollEnabled = scrollEnabled;


@end

在 UIPageViewController 禁用弹跳的解决方案:

    创建UIScrollView 类别(例如CustomScrolling)。 UIScrollView 已经是他们的手势识别器的代表了。 请注意,您的目标UIViewController(又名baseVC,内部带有UIPageViewController)通过AppDelegate 共享。否则,您可以使用运行时 (#import &lt;objc/runtime.h&gt;) 并将引用属性(到您的控制器 baseVC)添加到类别中。

    实现类别:

    @interface UIScrollView (CustomScrolling) <UIGestureRecognizerDelegate>
    @end
    
    @implementation UIScrollView (CustomScrolling)
    
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
    
        UIViewController * baseVC = [(AppDelegate *)[[UIApplication sharedApplication] delegate] baseVC];
        if (gestureRecognizer.view == baseVC.pageViewController.theScrollView) 
            NSInteger page = [baseVC selectedIndex];
            NSInteger total = [baseVC viewControllers].count;
            UIPanGestureRecognizer *recognizer = (UIPanGestureRecognizer *)gestureRecognizer;
            CGPoint velocity = [recognizer velocityInView:self];
            BOOL horizontalSwipe = fabs(velocity.x) > fabs(velocity.y);
            if (!horizontalSwipe) 
                return YES;
            
            BOOL scrollingFromLeftToRight = velocity.x > 0;
            if ((scrollingFromLeftToRight && page > 0) || (!scrollingFromLeftToRight && page < (total - 1))) 
                return YES;
            
            return NO;
        
        return YES;
    
    
    @end
    

    在您的baseVC 中导入类别文件#import "UIScrollView+CustomScrolling.h",该文件使用UIPageViewController。

【讨论】:

你能和全班分享一个要点吗? @el.severo 其实我已经做到了。只有一个弱点:在UIScrollView (CustomScrolling) 类别中获取指向baseVC 的指针。【参考方案13】:

这在viewDidLoad 中对我有用:

for subview in pager.view.subviews 
    if let scrollView = subview as? UIScrollView 
        scrollView.bounces = false
        scrollView.alwaysBounceHorizontal = false
        break
    

【讨论】:

【参考方案14】:

编辑:不要使用此解决方案。留在这里用于参考和教育目的我后来了解到,这会引入一个错误,其中大约 5% 的时间,用户无法在同一方向上翻页。他们必须向后翻页,然后再向前继续。

如果您使用的是UIPageViewControllerDataSource,一个相对简单的解决方法(并且有点老套)是在每次调用pageViewController:viewControllerBeforeViewController: 委托方法时禁用弹跳。这是一个示例实现:

@interface YourDataSourceObject ()
@property (strong, nonatomic) UIScrollView *scrollView;
@end

@implementation
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController 
    if (!self.scrollView) 
        for (UIView *view in pageViewController.view.subviews) 
            if ([view isKindOfClass:[UIScrollView class]]) 
                self.scrollView = (UIScrollView *)view;
            
        
    
    self.scrollView.bounces = NO;

    // Your other logic to return the correct view controller. 

@end

【讨论】:

您发布了“不要使用此解决方案”。为什么不简单地删除这个答案?你不会因此而失去任何分数。 @MichaelDautermann 我会把它留在这里。出于教育目的,看到不良模式也很好。由于 SO 就像一本巨大的去中心化手册,它很有价值 ;) 反弹 = NO 根本不起作用。它只是停止滚动。

以上是关于禁用 UIPageViewController 反弹的主要内容,如果未能解决你的问题,请参考以下文章

UIPageViewController 禁用滚动

仅在 uiPageViewController 中禁用临时向前滑动

禁用屏幕特定区域的 uipageviewcontroller 滑动

禁用 UIPageViewController 弹跳 - Swift [重复]

仅在 UIPageViewController 上的某个方向上禁用用户滑动?

如何在 UIPageViewController 上禁用多点触控?