ios – 禁用UIPageViewController中的反弹效果

参见英文答案 > Disable UIPageViewController bounce7个
我已经实现了一个包含两个页面的UIPageViewController.在最右边的页面上,我可以向右滑动,并将页面向后拉,以便当我释放时,它会弹回.当我向左滑动时,左侧页面上会出现同样的情况. (弹跳就像当你到达safari页面底部时会发生什么)

有没有办法禁用弹跳效果?谢谢!

解决方法

到目前为止,没有一个答案实际上完全有效.他们都失败的边缘案例是:

>滚动到第2页.
>使用一根手指拖到第1页.
>将第二根手指放在屏幕上,然后拖到第1页.
>提起第一根手指.
>重复,直到你已经拖过页面0.

在这种情况下,我看到的每个解决方案到目前为止,都超过了第0页的界限.核心问题是底层API被破坏,并开始报告相对于第0页的内容偏移量,而不用调用回调来让我们知道它显示不同的页面.在整个这个过程中,API仍然声称显示第1页,即使在第零页进入第-1页时,页面零.

这种设计缺陷的解决方法非常丑陋,但这里是:

@property (weak,nonatomic) UIPageControl *pageControl;
@property (nonatomic,assign) BOOL shouldBounce;
@property (nonatomic,assign) CGFloat lastPosition;
@property (nonatomic,assign) NSUInteger currentIndex;
@property (nonatomic,assign) NSUInteger nextIndex;

- (void)viewDidLoad {

    [super viewDidLoad];

...

    self.shouldBounce = NO;

    for (id testView in self.pageController.view.subviews) {
        UIScrollView *scrollView = (UIScrollView *)testView;
        if ([scrollView isKindOfClass:[UIScrollView class]]) {
            scrollView.delegate = self;
            // scrollView.bounces = self.shouldBounce;
        }
    }
}

- (NSInteger)presentationIndexForPageViewController:(UIPageViewController *)pageViewController{

    return (NSInteger)self.currentIndex;
}

- (void)pageViewController:(UIPageViewController *)pageViewController willTransitionToViewControllers:(NSArray *)pendingViewControllers{

    id controller = [pendingViewControllers firstObject];
    self.nextIndex = [viewControllers indexOfObject:controller];
}

- (void)pageViewController:(UIPageViewController *)pageViewController didFinishAnimating:(BOOL)finished prevIoUsViewControllers:(NSArray *)prevIoUsViewControllers transitionCompleted:(BOOL)completed{

    if(completed) {
        // At this point,we can safely query the API to ensure
        // that we are fully in sync,just in case.
        self.currentIndex = [viewControllers indexOfObject:[pageViewController.viewControllers objectAtIndex:0]];
        [self.pageControl setCurrentPage:self.currentIndex];
    }

    self.nextIndex = self.currentIndex;

}

- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
    /* The iOS page view controller API is broken.  It lies to us and tells us
       that the currently presented view hasn't changed,but under the hood,it
       starts giving the contentOffset relative to the next view.  The only
       way to detect this brain damage is to notice that the content offset is
       discontinuous,and pretend that the page changed.
     */
    if (self.nextIndex > self.currentIndex) {
        /* Scrolling forwards */

        if (scrollView.contentOffset.x < (self.lastPosition - (.9 * scrollView.bounds.size.width))) {
            self.currentIndex = self.nextIndex;
            [self.pageControl setCurrentPage:self.currentIndex];
        }
    } else {
        /* Scrolling backwards */

        if (scrollView.contentOffset.x > (self.lastPosition + (.9 * scrollView.bounds.size.width))) {
            self.currentIndex = self.nextIndex;
            [self.pageControl setCurrentPage:self.currentIndex];
        }
    }

    /* Need to calculate max/min offset for *every* page,not just the first and last. */
    CGFloat minXOffset = scrollView.bounds.size.width - (self.currentIndex * scrollView.bounds.size.width);
    CGFloat maxXOffset = (([viewControllers count] - self.currentIndex) * scrollView.bounds.size.width);

    NSLog(@"Page: %ld NextPage: %ld X: %lf MinOffset: %lf MaxOffset: %lf\n",(long)self.currentIndex,(long)self.nextIndex,(double)scrollView.contentOffset.x,(double)minXOffset,(double)maxXOffset);

    if (!self.shouldBounce) {
        CGRect scrollBounds = scrollView.bounds;
        if (scrollView.contentOffset.x <= minXOffset) {
            scrollView.contentOffset = CGPointMake(minXOffset,0);
            // scrollBounds.origin = CGPointMake(minXOffset,0);
        } else if (scrollView.contentOffset.x >= maxXOffset) {
            scrollView.contentOffset = CGPointMake(maxXOffset,0);
            // scrollBounds.origin = CGPointMake(maxXOffset,0);
        }
        [scrollView setBounds:scrollBounds];
    }
    self.lastPosition = scrollView.contentOffset.x;
}

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVeLocity:(CGPoint)veLocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
    /* Need to calculate max/min offset for *every* page,not just the first and last. */
    CGFloat minXOffset = scrollView.bounds.size.width - (self.currentIndex * scrollView.bounds.size.width);
    CGFloat maxXOffset = (([viewControllers count] - self.currentIndex) * scrollView.bounds.size.width);

    if (!self.shouldBounce) {
        if (scrollView.contentOffset.x <= minXOffset) {
            *targetContentOffset = CGPointMake(minXOffset,0);
        } else if (scrollView.contentOffset.x >= maxXOffset) {
            *targetContentOffset = CGPointMake(maxXOffset,0);
        }
    }
}

基本上,它记录每个滚动事件的偏移量.如果滚动位置与滚动方向相反的方向移动了一个不可能的距离(我任意挑选屏幕宽度的90%),代码假定iOS正在向我们说谎,并且表现得像转换正确完成,将偏移量视为相对于新页面而不是旧页面.

相关文章

UITabBarController 是 iOS 中用于管理和显示选项卡界面的一...
UITableView的重用机制避免了频繁创建和销毁单元格的开销,使...
Objective-C中,类的实例变量(instance variables)和属性(...
从内存管理的角度来看,block可以作为方法的传入参数是因为b...
WKWebView 是 iOS 开发中用于显示网页内容的组件,它是在 iO...
OC中常用的多线程编程技术: 1. NSThread NSThread是Objecti...