iosswiftuiscrollviewuipangesturerecognizer

How to make UIScrollView inside a UIScrollView act simultaneously


I'm using a UIScrollView (UIScrollView_1) with paging enabled to move between 3 pages horizontally.
On the last page there is multiple UIScrollViews (each one in its own cell) (UIScrollView_2), which when scrolling horizontally to the right (forward) displays the last page (loaded accordingly to which cell that was scrolled).
But if scrolling in the left direction (backwards) I want the UIScrollView_1 to take over and scroll back.
This works as intended if I move my finger up and register a new touch-event. But I want it to act simultaneously between both the UIScrollViews, on the same pan.

|-------------UIScrollView_1----------|    
| Page_1 | Page_2 |--UIScrollView_2---|  
..................|...Page_3|Page_4...|

What I want is to make use of the shouldRecognizeSimultaneouslyWith in the UIGestureRecognizerDelegate.
But when I trying to delegate both the UIScrollViews' to the same ViewController the error 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.' shows up on the ScrollView_2.

Any ideas on how to solve this?

UPDATE

Here's the cellForRow from page_3's UIViewController that not causing the error with the delegation, but where the UIScrollViews doesn't act simultaneously. (e.g need to move the finger up and down to detect the other UIScrollView.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "random", for: indexPath)
    return cell
}

Here's the cellForRow that causing the 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.'-error

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "random", for: indexPath)

    let scrollView_1_VC = self.parent
    cell.scrollView_2.panGestureRecognizer.delegate = scrollView_1_VC

    return cell
}

Solution

  • I solved it.
    The UIScrollView's built-in UIPanGestureRecognizer must be delegated to its own UIScrollView as the error 'UIScrollView's built-in pan gesture recognizer must have its scroll view as its delegate.' said.
    Instead subclass the UIScrollView and create a second UIPanGestureRecognizer which then acts simultaneously with the built-in UIPanGestureRecognizer.

    Step 1 - 4:

    1. Subclass the cell's UIScrollView and create a second UIPanGestureRecognizer.

    2. Add the UIGestureRecognizerDelegate to the CellScrollView and make the shouldRecognizeSimultaneouslyWith return true.
      The second UIPanGestureRecognizer will now act simultaneously with the built-in UIPanGestureRecognizer.

    class CellScrollView : UIScrollView, UIGestureRecognizerDelegate {   
        var panGesture : UIPanGestureRecognizer!
        
        override func awakeFromNib() {
            panGesture = UIPanGestureRecognizer.init(target: self, action: nil)
            addGestureRecognizer(panGesture)
         }
        
         func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
            return true
        }
    }
    
    1. In the cellForRow, make the newly created UIPanGestureRecognizer delegate to the UIScrollView_1's UIViewController.
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {        
        if medicines.isEmpty {
            return tableView.dequeueReusableCell(withIdentifier: "emptyMedCell", for: indexPath)
        }
        let cell = tableView.dequeueReusableCell(withIdentifier: "random", for: indexPath)
        let scrollView_1_VC = self.parent
        cell.cellScrollView.panGesture.delegate = scrollView_1_VC
        return cell
    }
    
    1. Lastly, in the ScrollView_1's UIViewController let the shouldRecognizeSimultaneouslyWith return true.
    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }