Progress of UIPageViewController

后端 未结 7 1067
礼貌的吻别
礼貌的吻别 2020-12-30 05:51

I would like to receive updates from the uipageviewcontroller during the page scrolling process. I want to know the transitionProgress in %. (This value should update when t

相关标签:
7条回答
  • 2020-12-30 06:02

    Based on Appgix solution, I'm adding this directly on my 'UIPageViewController' subclass. (Since I only need it on this one)

    For Swift 3:

    class MYPageViewControllerSubclass: UIPageViewController, UIScrollViewDelegate {
    
       override func viewDidLoad() {
              super.viewDidLoad()
    
              for subView in view.subviews {
                 if subView is UIScrollView {
                    (subView as! UIScrollView).delegate = self                
                 }
              }
        }
    
        // MARK: - Scroll View Delegate
    
        public func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let point = scrollView.contentOffset
            var percentComplete: CGFloat
            percentComplete = fabs(point.x - view.frame.size.width)/view.frame.size.width
            NSLog("percentComplete: %f", percentComplete)
        }
    
        // OTHER CODE GOES HERE...
    
    }
    
    0 讨论(0)
  • 2020-12-30 06:11

    in SWIFT to copy paste ;) works perfect for me

    extension UIPageViewController: UIScrollViewDelegate {
    
        public override func viewDidLoad() {
            super.viewDidLoad()
    
            for subview in view.subviews {
                if let scrollView = subview as? UIScrollView {
                    scrollView.delegate = self
                }
            }
        }
    
       public func scrollViewDidScroll(_ scrollView: UIScrollView) {
           let point = scrollView.contentOffset
           var percentComplete: CGFloat
           percentComplete = abs(point.x - view.frame.size.width)/view.frame.size.width
           print("percentComplete: ",percentComplete)
       }
    }
    
    0 讨论(0)
  • 2020-12-30 06:11

    Since I thought that the functionality of scrolling would stay forever, but that the internal implementation may change to something other than a scroll view, I found the solution below (I haven't tested this very much, but still)

    NSUInteger offset = 0;
    UIViewController * firstVisibleViewController;
    while([(firstVisibleViewController = [self viewControllerForPage:offset]).view superview] == nil) {
      ++offset;
    }
    CGRect rect = [[firstVisibleViewController.view superview] convertRect:firstVisibleViewController.view.frame fromView:self.view];
    CGFloat absolutePosition = rect.origin.x / self.view.frame.size.width;
    absolutePosition += (CGFloat)offset;
    

    (self is the UIPageViewController here, and [-viewControllerForPage:] is a method that returns the view controller at the given page)

    If absolutePosition is 0.0f, then the first view controller is shown, if it's equal to 1.0f, the second one is shown, etc... This can be called repeatedly in a CADisplayLink along with the delegate methods and/or UIPanGestureRecognizer to effectively know the status of the current progress of the UIPageViewController.

    EDIT: Made it work for any number of view controllers

    0 讨论(0)
  • 2020-12-30 06:13

    Use this -

    for (UIView *v in self.pageViewController.view.subviews) {
        if ([v isKindOfClass:[UIScrollView class]]) {
            ((UIScrollView *)v).delegate = self;
        }
    }
    

    to implement this protocol : -(void)scrollViewDidScroll:(UIScrollView *)scrollView

    and then use @xhist's code (modified) in this way

    -(void)scrollViewDidScroll:(UIScrollView *)scrollView
    {
    CGPoint point = scrollView.contentOffset;
    
    float percentComplete;
    percentComplete = fabs(point.x - self.view.frame.size.width)/self.view.frame.size.width;
    NSLog(@"percentComplete: %f", percentComplete);
    }
    
    0 讨论(0)
  • 2020-12-30 06:14

    KVO approach for Swift 4

    var myContext = 0
    
    override func viewDidLoad() {
        for view in self.view.subviews {
            if view is UIScrollView {
                view.addObserver(self, forKeyPath: "contentOffset", options: .new, context: &introPagingViewControllerContext)
            }
        }
    }
    
    // MARK: KVO
    
    override func observeValue(forKeyPath keyPath: String?,
                               of object: Any?,
                               change: [NSKeyValueChangeKey : Any]?,
                               context: UnsafeMutableRawPointer?)
    {
        guard let change = change else { return }
        if context != &myContext {
            super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
            return
        }
    
        if keyPath == "contentOffset" {
            if let contentOffset = change[NSKeyValueChangeKey.newKey] as? CGPoint {
                let screenWidth = UIScreen.main.bounds.width
                let percent = abs((contentOffset.x - screenWidth) / screenWidth)
                print(percent)
            }
        }
    }
    
    0 讨论(0)
  • 2020-12-30 06:21

    While Appgix' solution seemed to work at first, I noticed that when the user pans in a UIPageViewController, lifts the finger shortly and then immediately starts dragging again while the "snap-back" animation is NOT YET finished and then lifts his finger again (which will again "snap-back"), the scrollViewDidScroll method is only called when the page view controller finished the animation. For the progress calculation this means the second pan produces continuous values like 0.11, 0.13, 0.16 but when the scroll view snaps back the next progress value will be 1.0 which causes my other scroll view to be out of sync.

    To fight this I'm now listening to the scroll view's contentOffset key, which is still updated continuously in this situation.

    0 讨论(0)
提交回复
热议问题