Disable UIPageViewController bounce

前端 未结 13 2381
离开以前
离开以前 2020-11-27 04:08

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

Is it possible to disable the bounce effect of a UIPageViewController and still

相关标签:
13条回答
  • 2020-11-27 04:33

    In case you wish to disable scrollview on a UIPageViewController subclass entirely, you can use the snippet below. Note that this disables not only the bouncing but the horizontal scrolling of the pages as well.

    In my case I had a UISegmentedControl to switch between the pages in the PageViewController so disabling scrolling vertically was completely fine and working for me. Hope it helps someone else too.

    class MyPageViewController: UIPageViewController {
    
        private lazy var scrollView: UIScrollView = { view.subviews.compactMap({ $0 as? UIScrollView }).first! }()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            scrollView.isScrollEnabled = false
        }
    }
    
    0 讨论(0)
  • 2020-11-27 04:34

    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.

    0 讨论(0)
  • 2020-11-27 04:34

    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:

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

    Use the solution with searching scrollView reference in UIPageViewController subviews only for disabling scroll entirely:

    @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:

    1. Create UIScrollView category (for ex. CustomScrolling). UIScrollView is delegate of their gesture recognizer already.
    2. Be aware that your target UIViewController (aka baseVC with UIPageViewController inside) 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.

    0 讨论(0)
  • 2020-11-27 04:36

    Disable UIPageViewController's bounce

    Swift 2.2

    Addition to answers

    1) Add UIScrollViewDelegate to UIPageViewController

    extension PageViewController: UIScrollViewDelegate
    

    2) Add to viewDidLoad

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

    3) Add UIScrollViewDelegate methods

    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)
        }
    }
    
    0 讨论(0)
  • 2020-11-27 04:36

    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.

    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:

    @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
    
    0 讨论(0)
  • 2020-11-27 04:38

    If you keep track of your currentIndex then the below should be sufficient but its a little buggy because there is a random scenario where it stops scrolling altogether.

    I think the scrollView.bounces is a little buggy, perhaps I am missing something because most of the time it works fine, if anyone is able to have a solution based on the below it would be great please.

    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
        scrollView.bounces = currentIndex == 0 ||
            currentIndex == controllers.count - 1
            ? false 
            : true
    }
    
    0 讨论(0)
提交回复
热议问题