将父容器的平移手势移交给嵌套的UICollectionView

时间:2017-09-15 20:01:51

标签: ios iphone swift uiscrollview uipangesturerecognizer

我正在尝试构建一个复杂的拆分视图容器控制器,它有助于两个可变高度容器,每个容器都有自己的嵌套视图控制器。父控制器上有一个全局平移手势,允许用户在视图容器中的任何位置拖动,并在视图之间向上和向下滑动“分隔符”。它还有一些智能位置阈值检测逻辑,可以扩展任一视图(或重置分频器位置):

这很好用。还有很多代码可以构建它,我很乐意与大家分享,但我不认为这是相关的,所以暂时我会省略它。

我现在正试图通过向底部视图添加集合视图来使事情复杂化:

我已经能够解决这个问题,这样我就可以用一个决定性的平移手势滚动拆分视图,然后快速轻弹手指滚动收集视图(滑动手势,我想是吗?) ,但这是一个非常低级别的体验:你不能平移视图并同时滚动集合视图,并期望用户一致地复制相似但不同的手势以控制视图太难了互动。

为了尝试解决这个问题,我尝试了几种委托/协议解决方案,我在其中检测拆分视图中分隔符的位置,并启用/禁用canCancelTouchesInView和/或isUserInteractionEnable基于底视图是否完全展开的集合视图。这在某种程度上有效,但在以下两种情况下则不然:

  1. 当拆分视图分隔符处于其默认位置时,如果用户平移到底部视图完全展开的位置,然后继续平移,则集合视图应开始滚动直到手势结束。
  2. 当拆分视图分隔符位于顶部(底部容器视图完全展开)并且顶部的集合视图时,如果用户平移,则集合视图应滚动而不是拆分视图分隔符移动,直到集合视图到达其顶部位置,此时拆分视图应返回其默认位置。
  3. 这是一个说明此行为的动画:

    enter image description here

    鉴于此,我开始认为解决问题的唯一方法是在分割视图上创建一个委托方法,告诉集合视图底部视图处于最大高度,然后可以截取父级的平移手势或转发屏幕触摸到集合视图而不是?但是,我不知道该怎么做。如果我使用解决方案走在正确的轨道上,那么我的问题很简单:如何将平移手势转发或移交到集合视图并使集合视图以与触摸时相同的方式进行交互首先被它捕获了吗?我可以使用pointInsidetouches____方法做些什么吗?

    如果我不能这样做,我还能怎样解决这个问题?

    赏金猎人的更新:我有一些零碎的运气在集合视图上创建委托方法,并在拆分视图容器上调用它来设置属性shouldScroll,通过它我使用一些平移方向和定位信息以确定滚动视图是否应滚动。然后,我在UIGestureRecognizerDelegate的{​​{1}}委托方法中返回此值:

    gestureRecognizer:shouldReceive touch:

    这在开始滚动时可以正常工作,但在集合视图上启用滚动后效果不佳,因为滚动手势几乎总是覆盖平移手势。我想知道我是否可以用// protocol delegate protocol GalleryCollectionViewDelegate { var shouldScroll: Bool? { get } } // shouldScroll property private var _shouldScroll: Bool? = nil var shouldScroll: Bool { get { // Will attempt to retrieve delegate value, or self set value, or return false return self.galleryDelegate?.shouldScroll ?? self._shouldScroll ?? false } set { self._shouldScroll = newValue } } // UIGestureRecognizerDelegate method func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { return shouldScroll } // ---------------- // Delegate property/getter called on the split view controller and the logic: var shouldScroll: Bool? { get { return panTarget != self } } var panTarget: UIViewController! { get { // Use intelligent position detection to determine whether the pan should be // captured by the containing splitview or the gallery's collectionview switch (viewState.currentPosition, viewState.pan?.directionTravelled, galleryScene.galleryCollectionView.isScrolled) { case (.top, .up?, _), (.top, .down?, true): return galleryScene default: return self } } } 连接,但我还没有。

3 个答案:

答案 0 :(得分:3)

你不能放弃"一个手势,因为手势识别器保持相同的对象并且其view是不变的 - 它是手势识别器所附着的视图。

然而,没有什么可以阻止你告诉其他人查看如何回应手势。集合视图是一个滚动视图,因此您可以知道它是如何在每个时刻滚动的,并且可以并行执行其他操作。

答案 1 :(得分:3)

如何使底视图的子视图实际占用整个屏幕并将集合视图的contentInset.top设置为顶视图高度。然后在底部视图上方添加另一个子视图控制器。然后,您唯一需要做的就是让父视图控制器成为委托,以听取底部视图的集合视图的滚动偏移并更改顶视图的位置。没有复杂的手势识别器的东西。只有一个滚动视图(集合视图)

enter image description here

更新:试试这个!!

protocol TypeAProtocol {
...
}

protocol TypeBProtocol {
...
}

protocol SomeProtocol {
    associatedtype TypeA: TypeAProtocol
    associatedtype TypeB: TypeBProtocol

    var objA: TypeA? { get set }
    var objB: TypeB? { get set }
}

答案 2 :(得分:1)

您应该能够使用UICollectionViewDelegateFlowLayout通过单个集合视图实现您正在寻找的内容。如果你的顶视图需要任何特殊的滚动行为,例如视差,你仍然可以通过实现一个继承自UICollectionViewLayout的自定义布局对象在单个集合视图中实现这一点。

使用UICollectionViewDelegateFlowLayout方法比实现自定义布局更直接,因此如果您想要拍摄,请尝试以下方法:

  • 创建您的顶视图作为UICollectionViewCell的子类,并将其注册到您的集合视图。

  • 创建" divider"作为UICollectionViewCell的子类查看,并使用func register(_ viewClass: AnyClass?, forSupplementaryViewOfKind elementKind: String, withReuseIdentifier identifier: String)

  • 将其作为补充视图注册到您的集合视图中
  • 让您的集合视图控制器符合UICollectionViewDelegateFlowLayout,创建一个布局对象作为UICollectionViewFlowLayout的实例,将您的集合视图控制器指定为您的流布局实例的委托,并初始化您的集合查看您的流程布局。

  • 在您的collecton视图控制器中实现optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize返回每个不同视图的所需大小。