ScrollViewDetector.swift 2.54 KB
Newer Older
Zach Knox's avatar
Zach Knox committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//
//  ScrollViewDetector.swift
//  DeckTransition
//
//  Created by Harshil Shah on 06/12/17.
//  Copyright © 2017 Harshil Shah. All rights reserved.
//

import UIKit

/// An encapsulation for the logic used to parse a view controller hierarchy
/// and detect the scroll view to be tracked for the swipe-to-dismiss gesture
final class ScrollViewDetector {
    
    // MARK: - Public variables
    
    weak var scrollView: UIScrollView?
    
    // MARK: - Initializers
    
    init(withViewController viewController: UIViewController) {
        let topViewController = getVisibleViewController(fromViewController: viewController)
        self.scrollView = getScrollView(fromViewController: topViewController)
    }
    
    // MARK: - Private methods
    
    /// Returns the view controller whose `view` should be searched for the
    /// `UIScrollView` to track.
    ///
    /// - Parameter viewController: The view controller from which the search
    ///   should begin.
    /// - Returns: The view controller whose `view` must be searched.
    private func getVisibleViewController(fromViewController viewController: UIViewController) -> UIViewController {
        guard let deckViewController = viewController as? DeckTransitionViewControllerProtocol,
              let childViewController = deckViewController.childViewControllerForDeck as? UIViewController
        else {
            return viewController
        }
        
        return getVisibleViewController(fromViewController: childViewController)
    }
    
    /// Returns the `UIScrollView` which should be tracked.
    ///
    /// - Parameter viewController: The view controller whose view hierarchy
    ///   must be searched.
    /// - Returns: The scrollView specified in the
    ///   `DeckTransitionViewControllerProtocol` implementation if one exists,
    ///   failing which the lowermost `UIScrollView` in the view's top level
    ///   subviews, or nil if one isn't found.
    private func getScrollView(fromViewController viewController: UIViewController) -> UIScrollView? {
        if let deckViewController = viewController as? DeckTransitionViewControllerProtocol,
           let scrollView = deckViewController.scrollViewForDeck {
            return scrollView
        }
        
58
59
60
61
        if let scrollView = viewController.view as? UIScrollView {
            return scrollView
        }
        
Zach Knox's avatar
Zach Knox committed
62
63
64
65
66
67
68
69
70
71
        for subview in viewController.view.subviews {
            if let scrollView = subview as? UIScrollView {
                return scrollView
            }
        }
        
        return nil
    }
    
}