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
?
8 réponses
désactiver uipageviewcontroller's bounce
Ajouter
<UIScrollViewDelegate>
délégué à votre UIPageViewController de l'en-têtedé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; } }
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); } }
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);
}
}
désactiver uipageviewcontroller's bounce
Swift 2.2
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)
}
}
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
}
}
}
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);
}
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
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:
- Créer
UIScrollView
catégorie (p. ex. CustomScrolling).UIScrollView
est délégué de leur geste de reconnaissance déjà. - soyez conscient que votre cible
UIViewController
(aliasbaseVC
UIPageViewController
à l'intérieur) partagé parAppDelegate
. Sinon, vous pouvez utiliser de l'exécution (#import <objc/runtime.h>
) et ajouter la propriété de référence (à votre controllerbaseVC
) pour la catégorie. 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
catégorie Importation de fichier
#import "UIScrollView+CustomScrolling.h"
dans votrebaseVC
, qui utilise UIPageViewController.
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.
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)
}
}