我搜索了很多,但还没有找到合适的解决方案。
是否可能禁用UIPageViewController
的弹跳效果,并仍然使用UIPageViewControllerTransitionStyleScroll
?
我搜索了很多,但还没有找到合适的解决方案。
是否可能禁用UIPageViewController
的弹跳效果,并仍然使用UIPageViewControllerTransitionStyleScroll
?
应该实现UIScrollViewDelegate
方法来限制边缘滚动
class MyPageViewController: UIPageViewController {
override func loadView() {
super.loadView()
view.subviews.forEach { sv in
if let scrollView = sv as? UIScrollView {
scrollView.delegate = self
}
}
}
}
extension MyPageViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if currentPage == 0, scrollView.contentOffset.x + scrollView.contentInset.left < 0 {
scrollView.contentOffset = CGPoint(x: -scrollView.contentInset.left, y: scrollView.contentOffset.y)
}
else if currentPage == pageCount - 1, scrollView.contentInset.right < 0, scrollView.contentOffset.x + scrollView.contentInset.right > 0 {
scrollView.contentOffset = CGPoint(x: -scrollView.contentInset.right, y: scrollView.contentOffset.y)
}
}
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
if currentPage == 0, scrollView.contentOffset.x + scrollView.contentInset.left < 0 {
targetContentOffset.pointee = CGPoint(x: -scrollView.contentInset.left, y: targetContentOffset.pointee.y)
}
else if currentPage == pageCount - 1, scrollView.contentInset.right < 0, scrollView.contentOffset.x + scrollView.contentInset.right > 0 {
targetContentOffset.pointee = CGPoint(x: -scrollView.contentInset.right, y: targetContentOffset.pointee.y)
}
}
}
这里的currentPage
是当前页面索引,pageCount
是总页数。
要在UIPageViewController上禁用反弹,您可以这样做(在Swift 5中),假设您将myPages var声明为UIViewController数组:
// 添加滚动委托
class myController: UIPageViewController, UIScrollViewDelegate { ... }
// 声明 currentIdx 和 scrollview 变量
private var currentIdx: Int = 0
private var scrollview: UIScrollView?
// 在 ViewDidLoad 中,添加委托和股票滚动视图
for view in view.subviews {
if let subView = view as? UIScrollView {
subView.delegate = self
scrollview = subView
}
}
// 在你的代码中可以像这样检索当前索引
guard let currentViewController = viewControllers?.first, let currentIndex = myPages.firstIndex(of: currentViewController) else {
return
}
currentIdx = index
// 声明私有函数来计算需要的反弹次数
private func setBounces() {
let max = myPages.count - 1
scrollview?.bounces = currentIdx > 0 && currentIdx < max
}
// 添加UIScrollViewDelegate方法
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
setBounces()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
setBounces()
}
UIPageViewController实际上对你来说并没有太多用处。你可以很容易地使用带有视图控制器的UIScrollView,并禁用其弹跳效果。
只需像这样做
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);
}
UIPageViewController.scrollView
的弹跳效果,你肯定会导致pageViewController
出现问题:滑动操作将无法正常工作。所以,请不要这样做。self.theScrollView.alwaysBounceHorizontal = NO;
self.theScrollView.bounces = NO;
使用在UIPageViewController
子视图中搜索scrollView
引用的解决方案,以完全禁用滚动:
@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
UIScrollView
类别(例如CustomScrolling)。 UIScrollView
已经是其手势识别器的委托。UIViewController
(即内部带有UIPageViewController
的baseVC
)通过AppDelegate
共享。否则,您可以使用运行时(#import <objc/runtime.h>
)并将引用属性(到您的控制器baseVC
)添加到类别中。实现类别:
@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
在使用UIPageViewController的baseVC
中导入类别文件#import "UIScrollView+CustomScrolling.h"
。
UIScrollView (CustomScrolling)
类别中获取指向baseVC
的指针。 - sig编辑:不要使用此解决方案。仅供参考和教育目的后来我发现这会引入一个 bug,大约有 5% 的情况下,用户不能以同一方向翻页。他们必须返回到上一页,然后再次前进才能继续。
如果您正在使用 UIPageViewControllerDataSource
,一个相对简单的解决方法(有点 hacky)是在每次调用 pageViewController:viewControllerBeforeViewController:
代理方法时禁用弹跳。以下是一个示例实现:
@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
从UIPageViewController
的子视图中找到UIScrollView
实例,
然后将bounces
属性设置为false
,就可以轻松解决问题。
let vc = UIPageViewController(transitionStyle: UIPageViewController.TransitionStyle.scroll, navigationOrientation: UIPageViewController.NavigationOrientation.horizontal, options: [:])
for subview in vc.view.subviews {
if let scrollView = subview as? UIScrollView {
scrollView.bounces = false
break
}
}
这对我来说在viewDidLoad
中起了作用:
for subview in pager.view.subviews {
if let scrollView = subview as? UIScrollView {
scrollView.bounces = false
scrollView.alwaysBounceHorizontal = false
break
}
}