gpt4 book ai didi

ios - 将父容器的平移手势传递给嵌套的 UICollectionView

转载 作者:搜寻专家 更新时间:2023-10-30 22:37:06 25 4
gpt4 key购买 nike

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




这工作正常。还有很多代码来构建这个,我很乐意分享,但我认为它不相关,所以我暂时省略它。

我现在试图通过在底部 View 中添加一个集合 View 来使事情复杂化:



我已经能够解决这个问题,以便我可以使用决定性的平移手势向上滚动拆分 View ,并通过快速滑动手指(滑动手势,我想是?)来滚动集合 View ,但是这个是一种非常差的体验:您不能同时平移 View 和滚动集合 View ,并且期望用户始终如一地复制相似但不同的手势以控制 View 对于交互来说太困难了。

为了尝试解决这个问题,我尝试了几种委托(delegate)/协议(protocol)解决方案,在这些解决方案中我检测分割 View 中分隔符的位置并启用/禁用 canCancelTouchesInView和/或 isUserInteractionEnable在基于底部 View 是否完全展开的集合 View 上。这在一定程度上有效,但不适用于以下两种情况:

  • 当拆分 View 分隔线处于其默认位置时,如果用户向上平移到底部 View 完全展开的位置,然后继续向上平移,则集合 View 应该开始滚动直到手势结束。
  • 当拆分 View 分隔线位于顶部(底部容器 View 已完全展开)且集合 View 为 时不是 在顶部,如果用户向下平移,则集合 View 应滚动而不是拆分 View 分隔线移动,直到集合 View 到达其顶部位置,此时拆分 View 应返回其默认位置。

  • 这是说明此行为的动画:

    enter image description here

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

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

    赏金猎人更新:我在集合 View 上创建了一个委托(delegate)方法,并在拆分 View 容器上调用它以设置属性 shouldScroll ,通过它我使用一些平移方向和定位信息来确定 ScrollView 是否应该滚动。然后我在 UIGestureRecognizerDelegate 中返回这个值的 gestureRecognizer:shouldReceive touch:委托(delegate)方法:
    // 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
    }
    }
    }

    当您开始滚动时,这可以正常工作,但一旦在集合 View 上启用滚动,则效果不佳,因为滚动手势几乎总是覆盖平移手势。我想知道我是否可以与 gestureRecognizer:shouldRecognizeSimultaneouslyWith: 联系起来,但我还没到。

    最佳答案

    如何让底部 View 的 subview 实际上占据整个屏幕并将集合 View 的 contentInset.top 设置为顶部 View 高度。然后在底部 View 上方添加另一个 subview Controller 。然后你唯一需要做的就是让父 View Controller 成为代理来监听底部 View 的集合 View 的滚动偏移并改变顶部 View 的位置。没有复杂的手势识别器的东西。只有一个 ScrollView (集合 View )

    enter image description here

    更新:试试这个!!

    import Foundation
    import UIKit

    let topViewHeight: CGFloat = 250

    class SplitViewController: UIViewController, BottomViewControllerScrollDelegate {

    let topViewController: TopViewController = TopViewController()
    let bottomViewController: BottomViewController = BottomViewController()

    override func viewDidLoad() {
    super.viewDidLoad()

    automaticallyAdjustsScrollViewInsets = false

    bottomViewController.delegate = self
    addViewController(bottomViewController, frame: view.bounds, completion: nil)
    addViewController(topViewController, frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: topViewHeight), completion: nil)
    }

    func bottomViewScrollViewDidScroll(_ scrollView: UIScrollView) {
    print("\(scrollView.contentOffset.y)")

    let offset = (scrollView.contentOffset.y + topViewHeight)
    if offset < 0 {
    topViewController.view.frame.origin.y = 0
    topViewController.view.frame.size.height = topViewHeight - offset
    } else {
    topViewController.view.frame.origin.y = -(scrollView.contentOffset.y + topViewHeight)
    topViewController.view.frame.size.height = topViewHeight
    }
    }
    }

    class TopViewController: UIViewController {

    let label = UILabel()

    override func viewDidLoad() {
    super.viewDidLoad()

    automaticallyAdjustsScrollViewInsets = false
    view.backgroundColor = UIColor.red

    label.text = "Top View"
    view.addSubview(label)
    }

    override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    label.sizeToFit()
    label.center = view.center
    }
    }

    protocol BottomViewControllerScrollDelegate: class {
    func bottomViewScrollViewDidScroll(_ scrollView: UIScrollView)
    }

    class BottomViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

    var collectionView: UICollectionView!

    weak var delegate: BottomViewControllerScrollDelegate?

    let cellPadding: CGFloat = 5

    override func viewDidLoad() {
    super.viewDidLoad()

    view.backgroundColor = UIColor.yellow
    automaticallyAdjustsScrollViewInsets = false

    let layout = UICollectionViewFlowLayout()
    layout.minimumInteritemSpacing = cellPadding
    layout.minimumLineSpacing = cellPadding
    layout.scrollDirection = .vertical
    layout.sectionInset = UIEdgeInsets(top: cellPadding, left: 0, bottom: cellPadding, right: 0)

    collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
    collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    collectionView.contentInset.top = topViewHeight
    collectionView.scrollIndicatorInsets.top = topViewHeight
    collectionView.alwaysBounceVertical = true
    collectionView.backgroundColor = .clear
    collectionView.dataSource = self
    collectionView.delegate = self
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: String(describing: UICollectionViewCell.self))
    view.addSubview(collectionView)
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 30
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: UICollectionViewCell.self), for: indexPath)
    cell.backgroundColor = UIColor.darkGray
    return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let width = floor((collectionView.frame.size.width - 2 * cellPadding) / 3)
    return CGSize(width: width, height: width)
    }

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    delegate?.bottomViewScrollViewDidScroll(scrollView)
    }
    }

    extension UIViewController {

    func addViewController(_ viewController: UIViewController, frame: CGRect, completion: (()-> Void)?) {
    viewController.willMove(toParentViewController: self)
    viewController.beginAppearanceTransition(true, animated: false)
    addChildViewController(viewController)
    viewController.view.frame = frame
    viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
    view.addSubview(viewController.view)
    viewController.didMove(toParentViewController: self)
    viewController.endAppearanceTransition()
    completion?()
    }
    }

    关于ios - 将父容器的平移手势传递给嵌套的 UICollectionView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46246763/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com