Disable UIPageViewController bounce

a cherché beaucoup pour celui-ci, mais n'a pas pu trouver une solution appropriée encore.

Est-il possible de désactiver l'effet de rebond d'un UIPageViewController et encore UIPageViewControllerTransitionStyleScroll?

38
demandé sur Mario 2014-02-15 17:30:36

8 réponses

désactiver uipageviewcontroller's bounce

  1. Ajouter <UIScrollViewDelegate> délégué à votre UIPageViewController de l'en-tête

  2. définir les délégués de UIScrollView sous-jacents de L'UIPageViewController à leur parent dans viewDidLoad:

    for (UIView *view in self.view.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
            ((UIScrollView *)view).delegate = self;
            break;
        }
    }
    
  3. la mise en oeuvre de scrollViewDidScroll est de réinitialiser le contentOffset à l'origine (EN (0,0), mais (lié.taille.largeur, 0)) lorsque la l'utilisateur est d'atteindre des limites, comme ceci:

    - (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. enfin, la mise en oeuvre de scrollviewwillenddraging est de faire face à un scénario de bug lorsque l'utilisateur glisse rapidement de gauche à droite à la première page, la première page ne rebondit pas à gauche (en raison de la fonction ci-dessus), mais rebondit à droite causée par la (Peut-être) Vitesse du glissement. Et enfin, quand vous rebondirez, le UIPageViewController déclenchera un retournement de page vers le 2e page (ce qui est évidemment inattendu).

    - (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

Code à mettre dans viewDidLoad:

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

mise en oeuvre pour 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);
    }
}

mise en oeuvre pour scrollviewwillenddraging:

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);
    }
}
58
répondu Dong Ma 2018-07-24 13:13:18

désactiver uipageviewcontroller's bounce

Swift 2.2

Plus de réponses

1) Ajouter UIScrollViewDelegate à UIPageViewController

extension PageViewController: UIScrollViewDelegate

2) Ajouter à viewDidLoad

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

3) Ajouter les méthodes 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)
    }
}
13
répondu ZAV 2017-05-23 11:47:16

Je ne savais pas comment gérer correctement le currentIndex mais finit par le faire

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
        }
    }
}
3
répondu mwright 2017-03-23 11:40:49

UIPageViewController ne fait pas grand-chose pour vous. Vous pouvez utiliser un UIScrollView avec des contrôleurs de vue assez facilement, et désactiver le rebond sur cela.

Juste faire quelque chose comme

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);
}
1
répondu arsenius 2014-06-27 15:58:07

modifier: N'utilisez pas cette solution. j'ai appris par la suite que cela introduit un bug où environ 5% du temps, l'utilisateur ne peut pas paginer dans la même direction. Ils doivent revenir en arrière, puis avancer de nouveau pour continuer.

si vous utilisez un UIPageViewControllerDataSource, une solution relativement simple (et un peu hacky) est de désactiver rebondir à chaque fois le pageViewController:viewControllerBeforeViewController: la méthode delegate est appelée. Voici un exemple d'implémentation:

@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
répondu guptron 2015-12-13 17:19:03

si vous essayez de désactiver rebond pour UIPageViewController.scrollView, vous aurez certainement obtenir un cassé pageViewController: swipe ne va pas fonctionner. Ainsi, il ne faut pas faire:

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

utilisez la solution avec la recherche scrollView référence UIPageViewController sous-vues uniquement pour la désactivation de défilement entièrement:

@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

la Solution pour la désactivation de rebondir à UIPageViewController:

  1. Créer UIScrollView catégorie (p. ex. CustomScrolling). UIScrollView est délégué de leur geste de reconnaissance déjà.
  2. soyez conscient que votre cible UIViewController(alias baseVCUIPageViewController à l'intérieur) partagé par AppDelegate. Sinon, vous pouvez utiliser de l'exécution (#import <objc/runtime.h>) et ajouter la propriété de référence (à votre controller baseVC) pour la catégorie.
  3. mettre en oeuvre catégorie:

    @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. catégorie Importation de fichier #import "UIScrollView+CustomScrolling.h" dans votre baseVC, qui utilise UIPageViewController.

0
répondu sig 2018-07-03 12:18:09

une autre option est de définir ScrollView.bounce = false. Il a résolu mon problème avec pageviewcontroller's(bien sûr pas à propos de ScrollView) scrolling bounce. Le rebond est désactivé, et toutes les pages peuvent défiler sans rebond.

0
répondu Baron Michael B 2018-08-01 12:57:51

l'approche de@Dong Ma est parfaite mais elle peut être un peu améliorée et simplifiée.

Code à mettre dans viewDidLoad:

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

mise en oeuvre pour 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)
    }
  }

mise en oeuvre pour scrollviewwillenddraging:

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)
    }
  }
0
répondu KrLx_roller 2018-09-19 13:52:01