Search code examples
iosswiftuiscrollviewscrollviewswift4

Swift - Problem with scrollview (Need to print when dragging down)


I am testing the swiping controller/gesture from Jake Spracher with his SnapchatSwipeView (https://github.com/jakespracher/Snapchat-Swipe-View )

I have setup a topVC,leftVC,rightVC and middleVC(the main VC).

I manage to capture when the user swipe from the center to the rightVC or to the left VC, with this :

func scrollViewDidScroll(_ scrollView: UIScrollView) {

    if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled {
        let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y)
        
        self.scrollView!.setContentOffset(newOffset, animated:  false)   
    }
    
    if (scrollView.contentOffset) == CGPoint(x: 750.0, y: 0.0) {
        print ("TEST OK LEFT!")
         NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadRinkbox"), object: nil)
    }
    if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {
        print ("TEST OK LEFT!")
   }
    if (scrollView.contentOffset) == CGPoint(x: -750.0, y: 0.0) {
        print ("TEST OK RIGHT")  
    }
    if (scrollView.contentOffset) == CGPoint(x: 375, y: 0.0) {
        print ("TEST OK!")
     }
}

But I cannot manage to capture when the user swipe from the centerVC to the topVC, and from topVC to centerVC. I have tried a lot of things but I didn't manage to do it.

My code is for swift 4.

For clarity, I put here the two full swift files. Many, million thanks for those that can help me !

ContainerViewController.swift

//
//  ContainerViewController.swift
//  SnapchatSwipeView
//
//  Created by Jake Spracher on 8/9/15.
//  Copyright (c) 2015 Jake Spracher. All rights reserved.
//

import UIKit
import AVFoundation

protocol SnapContainerViewControllerDelegate {
    //  print "Snapcontainerview"
    func outerScrollViewShouldScroll() -> Bool
}

class SnapContainerViewController: UIViewController, UIScrollViewDelegate {
       var captureSession : AVCaptureSession!
    private var current: UIViewController
    //  print "2"
    var deeplink: DeeplinkType? {
        didSet {
            handleDeeplink()
        }
    }
    
    init() {
        current = SplashViewController()
        super.init(nibName:  nil, bundle: nil)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    var topVc: UIViewController?
    var leftVc: UIViewController!
    var middleVc: UIViewController!
    var rightVc: UIViewController!
    var bottomVc: UIViewController?
    
    var directionLockDisabled: Bool!
    
    var horizontalViews = [UIViewController]()
    var veritcalViews = [UIViewController]()
    
    var initialContentOffset = CGPoint() // scrollView initial offset
    var middleVertScrollVc: VerticalScrollViewController!
    var scrollView: UIScrollView!
    var delegate: SnapContainerViewControllerDelegate?
    
    class func containerViewWith(_ leftVC: UIViewController,
                                 middleVC: UIViewController,
                                 rightVC: UIViewController,
                                 topVC: UIViewController?=nil,
                                 bottomVC: UIViewController?=nil,
                                 directionLockDisabled: Bool?=false) -> SnapContainerViewController {
        let container = SnapContainerViewController()
        
 
        container.directionLockDisabled = directionLockDisabled
        
        container.topVc = topVC
        container.leftVc = leftVC
        container.middleVc = middleVC
        container.rightVc = rightVC
        container.bottomVc = bottomVC
        return container
    }
    
    
    var scrollOffSetClosure: ((_ offset: CGFloat) -> Void)?

       // code truncated for brevity

       func scrollViewDidScroll2(_ scrollView: UIScrollView) {
        scrollOffSetClosure!(scrollView.contentOffset.x)
        print("test here")
        
       }
    
    
    
    func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
        print("end scroll")
    }
    override func viewDidLoad() {
        super.viewDidLoad()
 
        addChildViewController(current)
        current.view.frame = view.bounds
        view.addSubview(current.view)
        current.didMove(toParentViewController: self)
 
    }
    
    func setupVerticalScrollView() {
        middleVertScrollVc = VerticalScrollViewController.verticalScrollVcWith(middleVc: middleVc as! Camera,
                                                                               topVc: topVc,
                                                                               bottomVc: bottomVc)
        delegate = middleVertScrollVc
 
        
        
    }
    
    func setupHorizontalScrollView() {
        scrollView = UIScrollView()
        scrollView.isPagingEnabled = true
        scrollView.showsHorizontalScrollIndicator = false
        scrollView.bounces = false
        print ("6")
        
        let view = (
            x: self.view.bounds.origin.x,
            y: self.view.bounds.origin.y,
            width: self.view.bounds.width,
            height: self.view.bounds.height
        )
        
        scrollView.frame = CGRect(x: view.x,
                                  y: view.y,
                                  width: view.width,
                                  height: view.height
        )
        
        self.view.addSubview(scrollView)
        
        let scrollWidth  = 3 * view.width
        let scrollHeight  = view.height
        scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight)
        
        leftVc.view.frame = CGRect(x: 0,
                                   y: 0,
                                   width: view.width,
                                   height: view.height
        )
        
        middleVertScrollVc.view.frame = CGRect(x: view.width,
                                               y: 0,
                                               width: view.width,
                                               height: view.height
        )
        
        rightVc.view.frame = CGRect(x: 2 * view.width,
                                    y: 0,
                                    width: view.width,
                                    height: view.height
        )
        
        addChildViewController(leftVc)
        addChildViewController(middleVertScrollVc)
        addChildViewController(rightVc)
        
        scrollView.addSubview(leftVc.view)
        scrollView.addSubview(middleVertScrollVc.view)
        scrollView.addSubview(rightVc.view)
        
        leftVc.didMove(toParentViewController: self)
        middleVertScrollVc.didMove(toParentViewController: self)
        rightVc.didMove(toParentViewController: self)
        
        scrollView.contentOffset.x = middleVertScrollVc.view.frame.origin.x
        scrollView.delegate = self
     
    }
    
    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
      //  print ("Scrollviewvillbegindragging scrollView.contentOffset \(scrollView.contentOffset)")
        self.initialContentOffset = scrollView.contentOffset
    }
    
    
  
     
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
 
      
        
        
        if delegate != nil && !delegate!.outerScrollViewShouldScroll() && !directionLockDisabled {
            let newOffset = CGPoint(x: self.initialContentOffset.x, y: self.initialContentOffset.y)
           // print(newOffset.x)
            //print(newOffset.y)
            // Setting the new offset to the scrollView makes it behave like a proper
            // directional lock, that allows you to scroll in only one direction at any given time
            self.scrollView!.setContentOffset(newOffset, animated:  false)
         //   print ("newOffset \(newOffset)")
            
            // tell child views they have appeared / disappeared
            
            
            
        }
     
        
        if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("aaa!")}
         if (scrollView.contentOffset) == CGPoint(x: 0.0, y: -667.0) {print ("bbb!")}
         if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 375) {print ("aaccca!")}
         if (scrollView.contentOffset) == CGPoint(x: 0.0, y: -375) {print ("ddddd!")}
         if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {print ("eeeeeee!")}
    //     if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("ffffff!")}
     //    if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 667.0) {print ("aggggggggaa!")}
        
        
       // print ("scrollViewDidScroll scrollView.contentOffset \(scrollView.contentOffset)")
       // scrollView.contentOffset
        if (scrollView.contentOffset) == CGPoint(x: 750.0, y: 0.0) {
            print ("TEST OK LEFT!")
             NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadRinkbox"), object: nil)
        }
        if (scrollView.contentOffset) == CGPoint(x: 0.0, y: 0.0) {
 
            
            print ("TEST OK RIGHT!")
  
        }
        if (scrollView.contentOffset) == CGPoint(x: -750.0, y: 0.0) {
            print ("TEST OK LEFT")
            
        }
        if (scrollView.contentOffset) == CGPoint(x: 375, y: 0.0) {
            print ("TEST LEFT/RIGHT OK!")
 
        }
    }
    
     
    
    private func animateFadeTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
        print ("Ca va dans animateFadeTransition")
        current.willMove(toParentViewController: nil)
        addChildViewController(new)
        transition(from: current, to: new, duration: 0.3, options: [.transitionCrossDissolve, .curveEaseOut], animations: {
            
        }) { completed in
            self.current.removeFromParentViewController()
            new.didMove(toParentViewController: self)
            self.current = new
            completion?()
        }
    }
    
    private func animateDismissTransition(to new: UIViewController, completion: (() -> Void)? = nil) {
        print ("Ca va dans animateDismissTransition")
        
        let initialFrame = CGRect(x: -view.bounds.width, y: 0, width: view.bounds.width, height: view.bounds.height)
        current.willMove(toParentViewController: nil)
        addChildViewController(new)
        new.view.frame = initialFrame
        
        transition(from: current, to: new, duration: 0.3, options: [], animations: {
            new.view.frame = self.view.bounds
        }) { completed in
            self.current.removeFromParentViewController()
            new.didMove(toParentViewController: self)
            self.current = new
            completion?()
        }
        
    }
    
 
    
}

and VerticalScrollViewController

/  MiddleScrollViewController.swift
//  SnapchatSwipeView
//
//  Created by Jake Spracher on 12/14/15.
//  Copyright © 2015 Jake Spracher. All rights reserved.
//
import UIKit

class VerticalScrollViewController: UIViewController, SnapContainerViewControllerDelegate {
    var topVc: UIViewController!
    var middleVc: UIViewController!
    var bottomVc: UIViewController!
    var scrollView: UIScrollView!
    
    class func verticalScrollVcWith(middleVc: UIViewController,
                                    topVc: UIViewController?=nil,
                                    bottomVc: UIViewController?=nil) -> VerticalScrollViewController {
        let middleScrollVc = VerticalScrollViewController()
        
        middleScrollVc.topVc = topVc
        middleScrollVc.middleVc = middleVc
        middleScrollVc.bottomVc = bottomVc
        
        return middleScrollVc
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view:
        setupScrollView()
    }
    
    func setupScrollView() {
        scrollView = UIScrollView()
        scrollView.isPagingEnabled = true
        scrollView.showsVerticalScrollIndicator = false
        scrollView.bounces = false
        
        let view = (
            x: self.view.bounds.origin.x,
            y: self.view.bounds.origin.y,
            width: self.view.bounds.width,
            height: self.view.bounds.height
        )
        
        scrollView.frame = CGRect(x: view.x, y: view.y, width: view.width, height: view.height)
        self.view.addSubview(scrollView)
        
        let scrollWidth: CGFloat  = view.width
        var scrollHeight: CGFloat
        
        switch (topVc, bottomVc) {
        case (nil, nil):
            scrollHeight  = view.height
            middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
            
            addChildViewController(middleVc)
            scrollView.addSubview(middleVc.view)
            middleVc.didMove(toParentViewController: self)
        case (_?, nil):
            scrollHeight  = 2 * view.height
            topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
            middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height)
            
            addChildViewController(topVc)
            addChildViewController(middleVc)
            
            scrollView.addSubview(topVc.view)
            scrollView.addSubview(middleVc.view)
            
            topVc.didMove(toParentViewController: self)
            middleVc.didMove(toParentViewController: self)
            
            scrollView.contentOffset.y = middleVc.view.frame.origin.y
        case (nil, _?):
            scrollHeight  = 2 * view.height
            middleVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
            bottomVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height)
            
            addChildViewController(middleVc)
            addChildViewController(bottomVc)
            
            scrollView.addSubview(middleVc.view)
            scrollView.addSubview(bottomVc.view)
            
            middleVc.didMove(toParentViewController: self)
            bottomVc.didMove(toParentViewController: self)
            
            scrollView.contentOffset.y = 0
        default:
            scrollHeight  = 3 * view.height
            topVc.view.frame = CGRect(x: 0, y: 0, width: view.width, height: view.height)
            middleVc.view.frame = CGRect(x: 0, y: view.height, width: view.width, height: view.height)
            bottomVc.view.frame = CGRect(x: 0, y: 2 * view.height, width: view.width, height: view.height)
            
            addChildViewController(topVc)
            addChildViewController(middleVc)
            addChildViewController(bottomVc)
            
            scrollView.addSubview(topVc.view)
            scrollView.addSubview(middleVc.view)
            scrollView.addSubview(bottomVc.view)
            
            topVc.didMove(toParentViewController: self)
            middleVc.didMove(toParentViewController: self)
            bottomVc.didMove(toParentViewController: self)
            
            scrollView.contentOffset.y = middleVc.view.frame.origin.y
        }
        
        scrollView.contentSize = CGSize(width: scrollWidth, height: scrollHeight)
    }

    // MARK: - SnapContainerViewControllerDelegate Methods
    
    func outerScrollViewShouldScroll() -> Bool {
        if scrollView.contentOffset.y < middleVc.view.frame.origin.y || scrollView.contentOffset.y > 2*middleVc.view.frame.origin.y {
            return false
        } else {
            return true
        }
    }
    
}

Solution

  • In MiddleScrollViewController.swift, make the controller conform to UIScrollViewDelegate:

    class VerticalScrollViewController: UIViewController,
                                        SnapContainerViewControllerDelegate,
                                        UIScrollViewDelegate {
    

    In that class, in setupScrollView(), set the delegate:

    func setupScrollView() {
        scrollView = UIScrollView()
        // set the delegate to self
        scrollView.delegate = self
        // the rest of the existing code...
    

    Still in that class, implement didScroll (or whatever other delegate funcs you want to handle):

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("Vertical Scroll - contentOffset:", scrollView.contentOffset)
    }
    

    Now you should get lots of print lines in the debug console when you scroll vertically:

    Vertical Scroll - contentOffset: (0.0, 561.0)
    Vertical Scroll - contentOffset: (0.0, 560.0)
    Vertical Scroll - contentOffset: (0.0, 559.0)
    Vertical Scroll - contentOffset: (0.0, 558.0)
    

    If you want your SnapContainerViewController class to be informed when vertical scrolling takes place, you'll probably want to use a new protocol/delegate so VerticalScrollViewController can send that information.