gpt4 book ai didi

ios - 将 UIScrollView 的交互转移到另一个 UIScrollView 中滚动

转载 作者:可可西里 更新时间:2023-11-01 01:07:53 30 4
gpt4 key购买 nike

我有一个具有以下结构的接口(interface),其中重要元素的名称在括号中:

- UIViewController
- UIScrollView (ScrollViewA)
- UIViewController (ProfileOverviewViewController)
- UIViewController (ProfileDetailViewController)
- UICollectionView (ScrollViewB)

所以基本上在另一个垂直 ScrollView (ScrollViewA) 中有一个垂直 ScrollView (ScrollViewB)。 ProfileOverviewViewControllerProfileDetailViewController 都是设备屏幕的大小,因此 ScrollViewB 只有在 ScrollViewA 滚动到时才可见底部。

分页在 ScrollViewA 上启用,因此捕捉到 ProfileOverviewViewController 获取整个屏幕 View 或 ProfileDetailViewController 获取整个屏幕 View 。

希望这张图能让布局更清晰一点: Layout

我的问题是:

  • 如果用户滚动到 ScrollViewA 的底部,以便 ProfileDetailViewControllerScrollViewB 可见。
  • 用户在 ScrollViewB 上向下滚动一点然后松开。
  • 然后用户在 ScrollViewB 上向上滚动。
  • 在仍然按住手指的同时,当用户到达 ScrollViewB 中内容的顶部时,ScrollViewB 应该停止滚动并且 ScrollViewA应该开始向上滚动到 ProfileOverviewViewController,所有这些都在用户的同一个手指手势内。

因为 bounces 属性为真,所以 ScrollViewB 不会简单地扩展到负的 y 内容偏移量。

ScrollViewB 的滚动到达顶部后如何转移到 ScrollViewA?

提前致谢

最佳答案

这是个很好的问题,我必须深入研究才能找到合适的解决方案。这是注释代码。这个想法是将自定义平移手势添加到 scrollViewB 并将 ProfileDetailViewController 设置为其手势委托(delegate)。当平移将 scrollViewB 带到其顶部时,ProfileOverviewViewController 会收到警告并开始滚动 scrollViewA。当用户松开手指时,ProfileOverviewViewController 决定是滚动到内容的底部还是顶部。

希望对您有所帮助:)

配置文件详细 View Controller :

//
// ProfileDetailViewController.swift
// Sandbox
//
// Created by Eric Blachère on 23/12/2018.
// Copyright © 2018 Eric Blachère. All rights reserved.
//

import UIKit

protocol OverflowDelegate: class {
func onOverflowEnded()
func onOverflow(delta: CGFloat)
}

/// State of overflow of scrollView
///
/// - on: The scrollview is overflowing : ScrollViewA should take the lead. We store the last trnaslation of the gesture
/// - off: No overflow detected
enum OverflowState {
case on(lastRecordedGestureTranslation: CGFloat)
case off

var isOn: Bool {
switch self {
case .on:
return true
case .off:
return false
}
}
}

class ProfileDetailViewController: UIViewController, UIScrollViewDelegate, UIGestureRecognizerDelegate {

@IBOutlet weak var scrollviewB: UIScrollView!

weak var delegate: OverflowDelegate?

/// a pan gesture added on scrollView B
var customPanGesture: UIPanGestureRecognizer!
/// The state of the overflow
var overflowState = OverflowState.off

override func viewDidLoad() {
super.viewDidLoad()

// create a custom pan gesture recognizer added on scrollview B. This way we can be delegate of this gesture & follow the finger
customPanGesture = UIPanGestureRecognizer(target: self, action: #selector(self.panRecognized(gesture:)))
scrollviewB.addGestureRecognizer(customPanGesture)
customPanGesture.delegate = self

scrollviewB.delegate = self
}


@objc func panRecognized(gesture: UIPanGestureRecognizer) {
switch overflowState {
case .on(let lastRecordedGestureTranslation):
// the user just released his finger
if gesture.state == .ended {
print("didEnd !!")
delegate?.onOverflowEnded() // warn delegate
overflowState = .off // end of overflow
scrollviewB.panGestureRecognizer.isEnabled = true // enable scroll again
return
}

// compute the translation delta & send it to delegate
let fullTranslationY = gesture.translation(in: view).y
let delta = fullTranslationY - lastRecordedGestureTranslation
overflowState = .on(lastRecordedGestureTranslation: fullTranslationY)
delegate?.onOverflow(delta: delta)
case .off:
return
}
}

func scrollViewDidScroll(_ scrollView: UIScrollView) {

if scrollView.contentOffset.y <= 0 { // scrollview B is at the top
// if the overflow is starting : initilize
if !overflowState.isOn {
let translation = self.customPanGesture.translation(in: self.view)
self.overflowState = .on(lastRecordedGestureTranslation: translation.y)

// disable scroll as we don't scroll in this scrollView from now on
scrollView.panGestureRecognizer.isEnabled = false
}
}
}

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true // so that both the pan gestures on scrollview will be triggered
}
}

全局 View Controller :

//
// GlobalViewController.swift
// Sandbox
//
// Created by Eric Blachère on 23/12/2018.
// Copyright © 2018 Eric Blachère. All rights reserved.
//

import UIKit

class GlobalViewController: UIViewController, OverflowDelegate {

@IBOutlet weak var scrollViewA: UIScrollView!

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
guard segue.identifier == "secondSegue", let ctrl = segue.destination as? ProfileDetailViewController else {
return
}
ctrl.delegate = self
}

func onOverflowEnded() {
// scroll to top if at least one third of the overview is showed (you can change this fraction as you please ^^)
let shouldScrollToTop = (scrollViewA.contentOffset.y <= 2 * scrollViewA.frame.height / 3)
if shouldScrollToTop {
scrollViewA.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
} else {
scrollViewA.scrollRectToVisible(CGRect(x: 0, y: scrollViewA.contentSize.height - 1, width: 1, height: 1), animated: true)
}
}

func onOverflow(delta: CGFloat) {
// move the scrollview content
if scrollViewA.contentOffset.y - delta <= scrollViewA.contentSize.height - scrollViewA.frame.height {
scrollViewA.contentOffset.y -= delta
print("difference : \(delta)")
print("contentOffset : \(scrollViewA.contentOffset.y)")
}
}
}

编辑:ProfileOverviewViewController 和 ProfileDetailViewController 是通过容器 View 在 Storyboard的 GlobalViewController 中设置的,但如果在代码中设置它应该也能正常工作;)

关于ios - 将 UIScrollView 的交互转移到另一个 UIScrollView 中滚动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53844951/

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