Search code examples
iosswiftuiscrollviewscroll-paging

Set video on old page to 0.0 seconds when scrolled to new page


I have a scrollView with pagingEnabled set to true. Each of these pages contains one video covering the entire screen. The videos are added using a for loop and a class called PlayerView (not only adding the video but also information about the video). Within the PlayerView class I have a function which starts/stops playing the video in the respective page and all that works fine.

My problem is I would like to set the video to the start of it and stop it there (at 0.0 seconds so to say) whenever the page containing that video is not visible anymore (with self.player?.seek(to: kCMTimeZero) and self.player?.pause()).

In my scrollView I have a function which detects what page has appeared and also states the previous page when the user scrolls from one page to another (in form of an index, e.g. when scrolled from page 2 to page 3 the function will print: "1 2"). To stick to the example: I would like to set the video on page 2 (index: 1) to 0 and pause it.

create scrollView (in class HomeController: UIViewController, UIScrollViewDelegate)

func initiateScrollView() {

    //create scrollView with paging enabled
    let scrollView = UIScrollView(frame: view.bounds)
    scrollView.isPagingEnabled = true
    scrollView.delegate = self
    view.addSubview(scrollView)

    //get page size
    let pageSize = view.bounds.size

    //three simple UIView are created (view1, view2, view3)

    //array with individual views
    let pagesViews = [view1, view2, view3]

    //amount of views
    let numberOfPages = pagesViews.count

    //add subviews (pages)
    for (pageIndex, page) in pagesViews.enumerated(){

        //add individual pages to scrollView
        page.frame = CGRect(origin: CGPoint(x:0 , y: CGFloat(pageIndex) * pageSize.height), size: pageSize)
        scrollView.addSubview(page)

        //add Subview with videoplayer frame to individual "pages"
        let videoPlayerFrame = CGRect(x: 0, y: 0, width: pageSize.width, height: pageSize.height)
        let videoPlayerView = PlayerView(frame: videoPlayerFrame)
        page.addSubview(videoPlayerView)

    }

    //adjust size of scrollView
    scrollView.contentSize = CGSize(width: pageSize.width, height: pageSize.height * CGFloat(numberOfPages))
}

Do you have an idea how to pause the video on the previous page? I would really appreciate your help!


Solution

  • There are about two ways I think you could do this depending on how exactly you want the video to stop.

    Method 1: The Video on the Previous View Stops and the Video on the New View Does Not Auto-Play

    You can create an Notification observer in each of the views which listens for a change of scroll view and fires a common function to stop the video (it is good practice to create a protocol to constrain these views to the common function although I will not do it here). So in each of the views you add an observer like this in the ViewDidLoad:

        NotificationCenter.default.addObserver(self, selector: #selector(ViewController.stopVideo), name: NSNotification.Name(rawValue: "stopVideo"), object: nil)
    

    And you add the corresponding function that will be called in the view:

        func stopVideo() {
    
            self.player.stop()
    
        }
    

    Then in your scrollview, in the function you mentioned that "detects what page has appeared and also states the previous page", you fire a notification whenever the scroll view changes:

        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "stopVideo"), object: nil)
    

    This will stop any video playing in all the views whenever there is a change of view. P.S Also remember to remove the observer in the deinit()

    Method 2: The Video on the Previous View Stops and the Video on the New View Does Will Auto-Play

    If the previous video will stop and new video will auto-play you could make a protocol for each of the views that they must adhere to like so:

        protocol StopVideoDelegate: class {
            func stopVideo()
            func startVideo()
        }
    

    Each of your views must implement this protocol, for example:

        class ViewController1InScrollView: StopVideoDelegate {
             func stopVideo() {
                 self.playerLayer.stop()
             }
             func startVideo() {
                 self.playerLayer.start()
             }
        }
    

    Then in your scrollview, in the function you mentioned that "detects what page has appeared and also states the previous page", can simply cast the previous view and next view to the protocol type and call the corresponding function:

        func theFunctionThatDetectsViewChangeInScrollView() {
            nextView as! StopVideoDelegate
            nextView.startVideo()
    
            previousView as! StopVideoDelegate
            previousView.stopVideo()
        }