Sliding conflict solution for nested UIScrollview

Although Apple suggested that we do not nest UIScrollview, but in the end this is what the developers say, can not stand the designer is to draw a design.
I met the scene like this, the top has a priority to show the cover, when the cover out of the screen after the contents of the ScrollView began rolling. Because the introduction, directory, evaluation of three tab can be left and right scrolling, so the specific content is nested in a ScrollView.

Sliding conflict solution for nested UIScrollview
Sliding conflict solution for nested UIScrollview

But in fact, the problems are similar, nested ScrollView, the need for a condition to control a particular moment which ScrollView response to the sliding event.

The first step is to control the response by setting the isScrollEnabled property of the ScrollView.

@IBOutlet weak var mainScrollView: UIScrollView @IBOutlet weak var subScrollView:! UIScrollView! Let maxOffsetY: CGFloat = 150 func scrollViewDidScroll (_ scrollView: UIScrollView) {if scrollView = = mainScrollView {if = scrollView.contentOffset.y & gt; maxOffsetY mainScrollView.isScrollEnabled = false subScrollView.isScrollEnabled = {true}}else {/ / when subScrollView sliding top, stop responding, mainScrollView response. If scrollView.contentOffset.y < = 0 {subScrollView.isScrollEnabled = false mainScrollView.isScrollEnabled =}}}

In the proxy method scrollViewDidScroll judge, when the mainScrollView draw 150, stop responding to the scroll, then the fingers slide, naturally is to display the contents of the subScrollView response.

But this simple scheme has a big drawback in practice. Users are not always perfect after sliding 150 Pt, stop. And then start the next slide. If the user once rolled 160, mainScrollView will stop after rolling to respond to the, because this is a gesture, subScrollView will not respond. The user will have the feeling of being interrupted, need second times to continue rolling.

So this simple and crude scheme can’t solve the problem. After all, the user is our dad.

Sliding conflict solution for nested UIScrollview

Everyone knows that every ScrollView has a panGestureRecognizer. At this point, we began to imagine, if you can control the pan gesture.
so we wrote this line of code and started trying:

MainScrollView.panGestureRecognizer.delegate = self

We all know that iOS development experience is particularly good, Apple’s API are particularly for everyone. Program run up Xcode will give you a crash:

‘UIScrollView’s built-in pan recognizer have its view as scroll its gesture must delegate.’

Let me translate:

Sliding conflict solution for nested UIScrollview

The solution is to add a linkage of our own pan gestures. Note that the shouldRecognizeSimultaneously in UIGestureRecognizerDelegate returns true.

Let pan = UIPanGestureRecognizer (target: self, action: #selector (ViewController.panGestureRecognizerAction (recognizer:)) pan.delegate) = self mainScrollView.addGestureRecognizer (Pan) func gestureRecognizer (gestureRecognizer: UIGestureRecognizer shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer _, -> Bool) {return true}

This setting can be used to obtain the parameters of the pan gesture without affecting the scroll.

Then we define two bool values to judge the current rolling ScrollView

Var mainScrollEnabled = var subScrollEnabled = false false

Set in scrollViewDidScroll:

Func scrollViewDidScroll (_ scrollView: UIScrollView) {if scrollView = = mainScrollView {if scrollView.contentOffset.y > maxOffsetY = {scrollView.setContentOffset (CGPoint (x: 0, y: maxOffsetY), animated: false mainScrollView.isScrollEnabled) = false subScrollView.isScrollEnabled = true subScrollEnabled = true}else scrollView.contentOffset.y {if} < {scrollView.setContentOffset = 0; CGPoint ((x: 0, y: 0). Animated: false subScrollView.isScrollEnabled mainScrollView.isScrollEnabled true) = false = mainScrollEnabled = true}}}

Then we deal with the problem of handling the sliding through the critical region in the recognizer of the pan gesture:

Var currentPanY: CGFloat = 0 func panGestureRecognizerAction (recognizer: UIPanGestureRecognizer) {if recognizer.state! =.Changed{currentPanY = 0 / / each sliding end empty state mainScrollEnabled = false subScrollEnabled = false}else {let currentY = recognizer.translation (in: mainScrollView) in the.Y / / in the process of sliding through the critical point if mainScrollEnabled subScrollEnabled || {if currentPanY = = 0 {currentPanY = currentY / / record after the critical point is y let offsetY} = currentPanY - currentY / / calculation at the critical point after offsetY if mainScro LlEnabled {let supposeY = maxOffsetY + offsetY if supposeY > = 0; mainScrollView.contentOffset = {CGPoint (x: 0, y: supposeY) {}else mainScrollView.contentOffset}}else {subScrollView.contentOffset = = CGPoint (x: 0, y: offsetY)}}}}

The disadvantage of this scheme is that the motion curve of the critical point is not natural. The native slip has a physical like elasticity, and we are directly set up by contentOffset, which is linear.

Welcome to pay attention to my micro-blog: @ no story