在UIScrollView中嵌套的UICollectionView之间的连续垂直滚动

虽然我知道嵌套的scrollView并不理想,但是我们的devise师为我提供了这个设置,所以我正在尽我所能使它工作。 让我们开始!

查看层次结构

  • 的UIView
    • UIScrollView (仅限垂直滚动)
      • 的UIImageView
      • UICollectionView#1(仅水平滚动)
      • UIImageView(与以前的UIImageView不同)
      • UICollectionView#2 (仅限垂直滚动)

重要的提示

我的所有视图都是使用程序化自动布局定义的。 UIScrollView子视图层次结构中的每个连续视图对其之前的视图具有y坐标依赖性。

问题

为了简单起见,让我们稍微修改一下术语:

  • _outerScrollView将引用UIScrollView
  • _innerScrollView将引用UICollectionView #2

我希望我的_innerScrollView在到达其contentSize底部时将其触摸事件路由到_innerScrollView 。 当我向后滚动时,我想要发生逆转。

目前,我有以下代码:

 - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { CGFloat bottomEdge = [scrollView contentOffset].y + CGRectGetHeight(scrollView.frame); if (bottomEdge >= [_outerScrollView contentSize].height) { _outerScrollView.scrollEnabled = NO; _innerScrollView.scrollEnabled = YES; } else { _outerScrollView.scrollEnabled = YES; _innerScrollView.scrollEnabled = NO; } } 

初始条件(在任何滚动发生之前)被设置为:

 outerScrollView.scrollEnabled = YES; innerScrollView.scrollEnabled = NO; 

怎么了?

在触摸视图时, outerScrollView滚动直到其底部边缘,然后由于_outerScrollView.bounces = YES;而产生橡皮筋效果_outerScrollView.bounces = YES; 如果我再次触摸视图,innerScrollView会滚动,直到它碰到底边。 在返回的路上,相同的橡皮筋效应以相反的顺序出现。 我想要发生的是两个子视图之间的stream畅运动。

很显然,这是由于代码片段中条件中设置的scrollEnabled条件造成的。 我想弄清楚的是如何将一个scrollView的速度/速度路由到下一个scrollView的边缘。

在这个问题上的任何援助将不胜感激。

其他说明

  1. 这不适合我: https : //github.com/ole/OLEContainerScrollView
  2. 我正在考虑把所有的UIScrollView层次结构(除了UICollectionView#2 )在UICollectionView#2的 supplementaryView 视图 。 不知道这是否会工作。

弄清楚了!

第一:

_scrollView.pagingEnabled = YES;

第二:

 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if (scrollView == _scrollView || scrollView == _offersCollectionView) { CGFloat offersCollectionViewPosition = _offersCollectionView.contentOffset.y; CGFloat scrollViewBottomEdge = [scrollView contentOffset].y + CGRectGetHeight(scrollView.frame); if (scrollViewBottomEdge >= [_scrollView contentSize].height) { _scrollView.scrollEnabled = NO; _offersCollectionView.scrollEnabled = YES; } else if (offersCollectionViewPosition <= 0.0f && [_offersCollectionView isScrollEnabled]) { [_scrollView scrollRectToVisible:[_scrollView frame] animated:YES]; _scrollView.scrollEnabled = YES; _offersCollectionView.scrollEnabled = NO; } } } 

哪里:

  • _scrollView_outerScrollView
  • _offersCollectionView_innerScrollView (这是我原来的postUICollectionView#2 )。

以下是现在发生的事情:

  • 当我向上滑动(所以视图向下移动)时, offersCollectionView将接pipe整个视图,将其他子视图移出视图。
  • 如果我向下滑动(所以意见了),其余的子视图回滚到scrollView的反弹效果的焦点。

接受的答案没有为我工作。 以下是做了什么:

定义UIScrollView的子类:

 class CollaborativeScrollView: UIScrollView, UIGestureRecognizerDelegate { var lastContentOffset: CGPoint = CGPoint(x: 0, y: 0) func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { return otherGestureRecognizer.view is CollaborativeScrollView } } 

由于不可能将触摸重新路由到另一个视图,所以确保外部滚动视图可以在内部一个停止时继续滚动的唯一方法是如果它一直在接收触摸。 然而,为了防止外层人员在内层人员移动,我们必须locking它,而不是设置其isScrollEnabledfalse ,否则它将停止接收触摸,并将无法拿起内层的地方当我们想要滚动内部的顶部或底部时停止。

这是通过分配滚动视图的UIScrollViewDelegate ,并实现scrollViewDidScroll(_:) ,如下所示:

 class YourViewController: UIViewController, UIScrollViewDelegate { private var mLockOuterScrollView = false @IBOutlet var mOuterScrollView: CollaborativeScrollView! @IBOutlet var mInnerScrollView: CollaborativeScrollView! enum Direction { case none, left, right, up, down } func viewDidLoad() { mOuterScrollView.delegate = self mInnerScrollView.delegate = self mInnerScrollView.bounces = false } func scrollViewDidScroll(_ scrollView: UIScrollView) { guard scrollView is CollaborativeScrollView else {return} let csv = scrollView as! CollaborativeScrollView //determine direction of scrolling var directionTemp: Direction? if csv.lastContentOffset.y > csv.contentOffset.y { directionTemp = .up } else if csv.lastContentOffset.y < csv.contentOffset.y { directionTemp = .down } guard let direction = directionTemp else {return} //lock outer scrollview if necessary if csv === mInnerScrollView { let isAlreadyAllTheWayDown = (mInnerScrollView.contentOffset.y + mInnerScrollView.frame.size.height) == mInnerScrollView.contentSize.height let isAlreadyAlltheWayUp = mInnerScrollView.contentOffset.y == 0 if (direction == .down && isAlreadyAllTheWayDown) || (direction == .up && isAlreadyAllTheWayUp) { mLockOuterScrollView = false } else { mLockOuterScrollView = true } } else if mLockOuterScrollView { mOuterScrollView.contentOffset = mOuterScrollView.lastContentOffset } csv.lastContentOffset = csv.contentOffset } } 

就是这样。 当你开始滚动内部滚动视图时,这将停止滚动外部滚动视图,并且当内部滚动视图一直滚动到其中一个末端时,再次获取滚动视图。