0

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
        }
    }
    
}
3
  • The only thing I presume is that ContainerViewController handles the VerticalScrollViewController, and the solution may be in the VerticalScrollViewController, but it has been a month of test and fails..it's just ridiculous.. Could someone kindly help ? Commented Feb 24, 2021 at 10:02
  • 1
    It can be difficult to get help when asking "how do I do this like in someOtherApp" ... because many folks will not have used someOtherApp. Try describing better what your goal is. For example: if I pull "middleVC" down to reveal "topVC" should I be able to pan horizontally to reveal "leftVC" and "rightVC"? Or do you want to allow horizontal scrolling only if "middleVC" is currently showing? Commented Feb 24, 2021 at 12:15
  • Hello @DongMag, What I want :when I am on the middleVC, and when I drag down, I would like to print a message ("dragged down") . For now, it is working for left and right. But when I go from middleVC to topVC, I cannot print any output. The func scrollViewDidScroll(_ scrollView: UIScrollView) does the job for the drag from Middle to right, or from middlevc to leftvc, but not from middleVC to topVC. I have tried UIGestureRecognizerDelegate or to put func scrollViewDidScroll(_ scrollView: UIScrollView) on the VerticalScrollViewController, but nothing is printed out Commented Feb 24, 2021 at 12:19

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.