Dre*_* K. 15 iphone bounce ios uipageviewcontroller
我已经实现了UIPageViewController
包含两个页面的内容.在最右边的页面上,我可以向右滑动,然后向后拉页面,这样当我释放时,它会反弹回来.当我向左滑动时左侧页面出现同样的情况.(弹跳就像到达野生动物园页面底部时发生的情况)
有没有办法禁用反弹效果?谢谢!
dga*_*ood 18
到目前为止,没有一个答案真正完全有效.他们都失败的边缘情况是这样的:
在那种情况下,我到目前为止看到的每个解决方案都超出了第0页的范围.核心问题是底层API被破坏,并开始报告相对于页面0的内容偏移量而不调用我们的回调告诉我们它显示的是不同的页面.在整个过程中,API仍然声称显示第1页,即使在第0页真正位于第-1页时也会显示第0页.
这个设计漏洞的解决方法非常难看,但它是:
@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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上,它记录每个滚动事件的偏移量.如果滚动位置在与滚动方向相反的方向上移动了不可能的距离(我任意选择了屏幕宽度的90%),则代码假定iOS对我们说谎,并且表现得好像过渡正确完成,将偏移视为相对于新页面而不是旧页面.
这是一个简单的解决方案
fileprivate var currentIndex = 0
fileprivate var lastPosition: CGFloat = 0
override func viewDidLoad() {
super.viewDidLoad()
for view in view.subviews {
if view is UIScrollView {
(view as! UIScrollView).delegate = self
break
}
}
}
func pageViewController(_ pageViewController: UIPageViewController,
didFinishAnimating finished: Bool,
previousViewControllers: [UIViewController],
transitionCompleted completed: Bool) {
if completed {
// Get current index
let pageContentViewController = pageViewController.viewControllers![0]
currentIndex = orderedViewControllers.index(of: pageContentViewController)!
}
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.lastPosition = scrollView.contentOffset.x
if (currentIndex == orderedViewControllers.count - 1) && (lastPosition > scrollView.frame.width) {
scrollView.contentOffset.x = scrollView.frame.width
return
} else if currentIndex == 0 && lastPosition < scrollView.frame.width {
scrollView.contentOffset.x = scrollView.frame.width
return
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
16814 次 |
最近记录: |