我正在尝试构建一个复杂的拆分视图容器控制器,它有助于两个可变高度容器,每个容器都有自己的嵌套视图控制器。父控制器上有一个全局平移手势,允许用户在视图容器中的任何位置拖动,并在视图之间向上和向下滑动“分隔符”。它还有一些智能位置阈值检测逻辑,可以扩展任一视图(或重置分频器位置):
这很好用。还有很多代码可以构建它,我很乐意与大家分享,但我不认为这是相关的,所以暂时我会省略它。
我现在正试图通过向底部视图添加集合视图来使事情复杂化:
我已经能够解决这个问题,这样我就可以用一个决定性的平移手势滚动拆分视图,然后快速轻弹手指滚动收集视图(滑动手势,我想是吗?) ,但这是一个非常低级别的体验:你不能平移视图并同时滚动集合视图,并期望用户一致地复制相似但不同的手势以控制视图太难了互动。
为了尝试解决这个问题,我尝试了几种委托/协议解决方案,我在其中检测拆分视图中分隔符的位置,并启用/禁用canCancelTouchesInView
和/或isUserInteractionEnable
基于底视图是否完全展开的集合视图。这在某种程度上有效,但在以下两种情况下则不然:
这是一个说明此行为的动画:
鉴于此,我开始认为解决问题的唯一方法是在分割视图上创建一个委托方法,告诉集合视图底部视图处于最大高度,然后可以截取父级的平移手势或转发屏幕触摸到集合视图而不是?但是,我不知道该怎么做。如果我使用解决方案走在正确的轨道上,那么我的问题很简单:如何将平移手势转发或移交到集合视图并使集合视图以与触摸时相同的方式进行交互首先被它捕获了吗?我可以使用pointInside
或touches____
方法做些什么吗?
如果我不能这样做,我还能怎样解决这个问题?
赏金猎人的更新:我有一些零碎的运气在集合视图上创建委托方法,并在拆分视图容器上调用它来设置属性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
}
}
}
连接,但我还没有。
答案 0 :(得分:3)
你不能放弃"一个手势,因为手势识别器保持相同的对象并且其view
是不变的 - 它是手势识别器所附着的视图。
然而,没有什么可以阻止你告诉其他人查看如何回应手势。集合视图是一个滚动视图,因此您可以知道它是如何在每个时刻滚动的,并且可以并行执行其他操作。
答案 1 :(得分:3)
如何使底视图的子视图实际占用整个屏幕并将集合视图的contentInset.top设置为顶视图高度。然后在底部视图上方添加另一个子视图控制器。然后,您唯一需要做的就是让父视图控制器成为委托,以听取底部视图的集合视图的滚动偏移并更改顶视图的位置。没有复杂的手势识别器的东西。只有一个滚动视图(集合视图)
更新:试试这个!!
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
返回每个不同视图的所需大小。