禁用UIPageViewController中的跳出效果 [英] Disable bounce effect in UIPageViewController

查看:99
本文介绍了禁用UIPageViewController中的跳出效果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了一个包含两个页面的 UIPageViewController 。在最右边的页面上,我可以向右滑动,然后向后拉页面,这样当我释放时,它会反弹回来。当我向左滑动时左侧页面出现同样的情况。 (弹跳就像当你到达野生动物园页面的底部时发生的事情)

I have implemented a UIPageViewController that contains two pages. On the right most page, I am able to swipe to the right, and pull the page back so that when I release, it bounces back. The same thing occurs on the left page when I swipe to the left. (The bouncing is like what happens when you reach the bottom of a safari page)

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

Is there a way to disable the bounce effect? Thanks!

推荐答案

到目前为止,没有一个答案能够完全发挥作用。他们都失败的边缘情况是:

Thus far, none of the answers actually work fully. The edge case that they all fail on is this:


  1. 滚动到第2页。

  2. 使用一根手指,向第1页拖动。

  3. 将第二根手指放在屏幕上并向第1页拖动。

  4. 抬起第一根手指。

  5. 重复,直到你拖过第0页。

  1. Scroll to page 2.
  2. Using one finger, drag towards page 1.
  3. Place a second finger on the screen and drag towards page 1.
  4. Lift the first finger.
  5. Repeat until you have dragged past page 0.

在那种情况下,每个解决方案我都是到目前为止看到的已超过第0页的界限。核心问题是底层API被破坏,并开始报告相对于页面0的内容偏移量而不调用我们的回调告诉我们它正在显示不同的页面。在整个过程中,API仍然声称显示第1页,即使在第0页真正位于第-1页时也会显示第0页。

In that situation, every solution I've seen so far goes past the bounds of page 0. The core problem is that the underlying API is broken, and begins reporting a content offset relative to page 0 without calling our callback to let us know that it is showing a different page. Throughout this process, the API still claims to be showing page 1, going towards page zero even while it is really on page zero going towards page -1.

这个设计缺陷非常难看,但这里是:

The workaround for this design flaw is remarkably ugly, but here it is:

@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对我们说谎,并且表现得好像过渡正确完成,将偏移视为相对于新页面而不是旧页面。

Basically, it records the offset for each scroll event. If the scroll position has moved a distance that is impossible (I arbitrarily picked 90% of the width of the screen) in the opposite direction from the direction of scrolling, the code assumes that iOS is lying to us, and behaves as though the transition finished properly, treating the offsets as being relative to the new page instead of the old one.

这篇关于禁用UIPageViewController中的跳出效果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆