ios 禁用 UIPageViewController 弹跳

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21798218/
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-08-30 23:27:21  来源:igfitidea点击:

Disable UIPageViewController bounce

iosiphoneobjective-cuipageviewcontroller

提问by Mario

Searched a lot for this one, but couldn't find a proper solution yet.

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

Is it possible to disable the bounce effect of a UIPageViewControllerand still use the UIPageViewControllerTransitionStyleScroll?

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

回答by Dong Ma

Disable UIPageViewController's bounce

禁用 UIPageViewController 的弹跳

  1. Add the <UIScrollViewDelegate>delegate to your UIPageViewController's header

  2. Set the UIPageViewController's underlying UIScrollView's delegates to their parent in viewDidLoad:

    for (UIView *view in self.view.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
            ((UIScrollView *)view).delegate = self;
            break;
        }
    }
    
  3. The implementation for scrollViewDidScrollis to reset the contentOffset to the origin (NOT (0,0), but (bound.size.width, 0)) when the user is reaching out of the bounds, like this:

    - (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);
        }
    }
    
  4. Finally, the implementation for scrollViewWillEndDraggingis to deal with a bug scenario when the user quickly swipes from left to right at the first page, the first page won't bounce at the left (due to the function above), but will bounce at the right caused by the (maybe) velocity of the swipe. And finally when bounced back, the UIPageViewController will trigger a page flip to the 2nd page (which is of course, not expected).

    - (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);
        }
    }
    
  1. <UIScrollViewDelegate>委托添加到 UIPageViewController 的标题中

  2. 将 UIPageViewController 的底层 UIScrollView 的委托设置为它们的父级viewDidLoad

    for (UIView *view in self.view.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
            ((UIScrollView *)view).delegate = self;
            break;
        }
    }
    
  3. scrollViewDidScroll的实现是在用户超出边界时将 contentOffset 重置为原点(NOT (0,0), but (bound.size.width, 0)),如下所示:

    - (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);
        }
    }
    
  4. 最后,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);
        }
    }
    

Swift 4.0

斯威夫特 4.0

Code to put into viewDidLoad:

要放入的代码viewDidLoad

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

Implementation for scrollViewDidScroll:

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

Implementation for scrollViewWillEndDragging:

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

回答by ZAV

Disable UIPageViewController's bounce

禁用 UIPageViewController 的弹跳

Swift 2.2

斯威夫特 2.2

Addition to answers

对答案的补充

1) Add UIScrollViewDelegate to UIPageViewController

1) 将 UIScrollViewDelegate 添加到 UIPageViewController

extension PageViewController: UIScrollViewDelegate

2) Add to viewDidLoad

2) 添加到 viewDidLoad

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

3) Add UIScrollViewDelegate methods

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)
    }
}

回答by mwright

I wasn't sure how to correctly manage the currentIndexbut ended up doing

我不确定如何正确管理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
        }
    }
}

回答by PERIPERI

Another option is to set ScrollView.bounce = false. It solved my problem with pageViewController's(Of course not about ScrollView) scrolling bounce. Bounce is disabled, and all page can scroll without bounces.

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

回答by arsenius

UIPageViewController doesn't actually do much for you. You can use a UIScrollView with view controllers quite easily, and disable the bounce on that.

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

Just do something like

只是做类似的事情

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

回答by Kamil Harasimowicz

Edited answer of Dong Ma, where:

东马的编辑答案,其中:

  • added - respects layout direction (Hebrew for example)
  • fixed - wrong counting currentIndexwhen swipes very quick
  • 添加 - 尊重布局方向(例如希伯来语)
  • 固定 -currentIndex快速滑动时错误计数

Info:

信息:

  • Written in Swift 5.0
  • Builded and tested in Xcode 10.2.1
  • iOS 12.0
  • 用 Swift 5.0 编写
  • 在 Xcode 10.2.1 中构建和测试
  • iOS 12.0

How to:

如何:

  1. Let's assume we have a UIViewControllerwhere UIPageViewControlleris added as child VC.
  1. 假设我们有一个UIViewControllerwhereUIPageViewController被添加为子 VC。
class ViewController: UIViewController {
    var pageNavigationController: UIPageViewController! 

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

    // rest of UI's setups  
}
  1. Set ViewControlleras delegate of UIPageViewController:
  1. 设置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
    }
}
  1. Set ViewControlleras datasource of UIPageController:
  1. 设置ViewController为以下数据源UIPageController
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
    }
}
  1. "Disable" bouncing by setting ViewControlleras delegate of UIPageViewController's UIScrollView:
  1. 通过设置ViewControllerUIPageViewController's 的代表来“禁用”弹跳UIScrollView
// 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")
        }
    }
}

回答by HassanElDesouky

My solution in Swift 5
In my scenario, I first load the UIPageViewControlleron the second page. And I have a total of three pages so I open on the middle one.

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

Here's the code of my 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
  }
}

回答by sig

If you will try to disable bounce for UIPageViewController.scrollView, you will definitely get a broken pageViewController: swipe ain't gonna work. So, don't do that:

如果您尝试为 禁用弹跳UIPageViewController.scrollView,您肯定会遇到问题pageViewController:刷卡是行不通的。所以,不要这样做:

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

Use the solution with searching scrollViewreference in UIPageViewControllersubviews only for disabling scroll entirely:

scrollViewUIPageViewController子视图中使用带有搜索参考的解决方案仅用于完全禁用滚动:

@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

Solution for disabling bounce at UIPageViewController:

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

  1. Create UIScrollViewcategory (for ex. CustomScrolling). UIScrollViewis delegate of their gesture recognizer already.
  2. Be aware that your target UIViewController(aka baseVCwith UIPageViewControllerinside) shared via AppDelegate. Otherwise you can use run-time (#import <objc/runtime.h>) and add reference property (to your controller baseVC) to the category.
  3. Implement category:

    @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
    
  4. Import category file #import "UIScrollView+CustomScrolling.h"in your baseVC, that uses UIPageViewController.

  1. 创建UIScrollView类别(例如 CustomScrolling)。UIScrollView已经是他们的手势识别器的代表了。
  2. 要知道,你的目标UIViewController(又名baseVCUIPageViewController内)通过共享AppDelegate。否则,您可以使用运行时 ( #import <objc/runtime.h>) 并将引用属性(到您的控制器baseVC)添加到类别中。
  3. 实施类别:

    @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
    
  4. #import "UIScrollView+CustomScrolling.h"baseVC使用 UIPageViewController.js 的 .xml文件中导入类别文件。

回答by guptron

Edit: Do not use this solution.I learned afterwards that this introduces a bug where about 5% of the time, the user can't page in the same direction. They have to page back, then forward again to continue.

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

If you're using a UIPageViewControllerDataSource, a relatively simple workaround (and a bit hacky) is to disable bouncing each time the pageViewController:viewControllerBeforeViewController:delegate method is called. Here is an example implementation:

如果您使用的是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

回答by anonymous

@Dong Ma's approach is perfect but it can be a little bit improved and simplified.

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

Code to put into viewDidLoad:

放入viewDidLoad 的代码:

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

Implementation for scrollViewDidScroll:

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)
    }
  }

Implementation for scrollViewWillEndDragging:

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)
    }
  }