【发布时间】:2018-02-25 01:41:39
【问题描述】:
我正在尝试构建一个复杂的拆分视图容器控制器,以方便两个可变高度容器,每个容器都有自己的嵌套视图控制器。父控制器上有一个全局平移手势,允许用户拖动视图容器中的任何位置,并在视图之间上下滑动“分隔线”。它还具有一些智能位置阈值检测逻辑,可以扩展任一视图(或重置分隔线位置):
这很好用。还有很多代码来构建这个,我很乐意分享,但我认为它不相关,所以我暂时省略它。
我现在试图通过在底部视图中添加一个集合视图来使事情复杂化:
我已经解决了这个问题,这样我就可以用一个决定性的平移手势向上滚动拆分视图,并用手指快速滑动来滚动集合视图(我想是滑动手势?) ,但这是一个非常低级的体验:您不能同时平移视图和滚动集合视图,并且期望用户始终如一地复制相似但不同的手势以控制视图太难了互动。
为了解决这个问题,我尝试了几种委托/协议解决方案,在这些解决方案中,我检测拆分视图中分隔线的位置,并根据底部视图是否完全展开。这在一定程度上有效,但不适用于以下两种情况:
- 当拆分视图分隔线处于其默认位置时,如果用户向上平移到底部视图完全展开的位置,然后继续向上平移,则集合视图应开始滚动,直到手势结束。
- 当拆分视图分隔线位于顶部(底部容器视图已完全展开)且集合视图不位于顶部时,如果用户向下平移,则集合视图应滚动而不是滚动拆分视图分隔线移动,直到集合视图到达其顶部位置,此时拆分视图应返回其默认位置。
这是一个说明这种行为的动画:
鉴于此,我开始认为解决问题的唯一方法是在拆分视图上创建一个委托方法,该方法告诉集合视图何时底部视图处于最大高度,然后可以拦截父级的平移手势或将屏幕触摸转发到集合视图?但是,我不知道该怎么做。如果我在正确的轨道上找到了解决方案,那么我的问题很简单:如何将平移手势转发或移交给集合视图,并让集合视图以与触摸时相同的方式交互一开始就被它捕获了?我可以用pointInside或touches____方法做点什么吗?
如果我不能这样做,我还能如何解决这个问题?
赏金猎人更新:我有一些零碎的运气在集合视图上创建一个委托方法,并在拆分视图容器上调用它来设置一个属性shouldScroll,通过它我使用一些平移方向和定位信息确定滚动视图是否应该滚动。然后我在UIGestureRecognizerDelegate的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
}
}
}
这适用于您开始滚动时,但在集合视图上启用滚动后效果不佳,因为滚动手势几乎总是会覆盖平移手势。我想知道是否可以与gestureRecognizer:shouldRecognizeSimultaneouslyWith: 联系,但我还没有。
【问题讨论】:
-
你能分享你的代码来测试这个行为吗?在您提到的两种情况中的任何一种中,collectionView 似乎都应该使用触摸事件,直到其水平偏移量达到其边界,这似乎相当简单。
-
@Lukas 我可以,但我不确定它是否真的有助于解决问题 - 既是因为在 IB 中内置了很多具有 IB 约束的功能,而且因为您已经知道我有检测委托完全按照您描述的方式触发的方法:“当水平偏移量达到其上限时,collectionView 应该使用触摸事件。”不过,如果你想要一些代码,我可以添加一些
¯\_(ツ)_/¯
标签: ios iphone swift uiscrollview uipangesturerecognizer