在 tableview 滚动和再次拖动 tableview 上动画 UIView 位置

Posted

技术标签:

【中文标题】在 tableview 滚动和再次拖动 tableview 上动画 UIView 位置【英文标题】:Animate UIView position on tableview scroll and again tableview drag 【发布时间】:2020-06-03 11:25:55 【问题描述】:

我有一个项目列表,顶部有一个标题菜单。

当用户向上滚动菜单时,菜单也应该滚出屏幕,当他们返回列表顶部时,菜单应该是可见的。

tableViewHeader 的行为方式大致相同。

但是,如果标题不在屏幕上并且用户在列表上结束了向下拖动,则此标题视图应该从顶部向下动画。如果用户随后在列表中向上拖动,则标题应以动画方式退出屏幕。

我已经实现了下面的第一部分,但是我正在努力实现动画效果。

我曾考虑为菜单使用 2 个视图,一个可以滚动,另一个可以为其位置设置动画,但是这感觉不对,我相信一定有更好的方法,而不会重复视图。

class TableViewScene: UIViewController 

  let data = Array(0...99)

  var headerViewOneTopConstraint: NSLayoutConstraint!
  var tableViewTopConstraint: NSLayoutConstraint!

  lazy var headerViewOne: UIView = 
    let view = UIView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.backgroundColor = .purple
    return view
  ()

  lazy var tableView: UITableView = 
    let view = UITableView(frame: .zero)
    view.translatesAutoresizingMaskIntoConstraints = false
    view.delegate = self
    view.dataSource = self
    view.tableFooterView = .init()
    view.refreshControl = .init()
    return view
  ()

  override func viewDidLoad() 
    super.viewDidLoad()

    navigationController?.navigationBar.isTranslucent = false

    headerViewOneTopConstraint = headerViewOne.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor)
    tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 184)

    [headerViewOne, tableView].forEach(view.addSubview)

    NSLayoutConstraint.activate([
      headerViewOneTopConstraint,
      headerViewOne.leadingAnchor.constraint(equalTo: view.leadingAnchor),
      headerViewOne.trailingAnchor.constraint(equalTo: view.trailingAnchor),
      headerViewOne.heightAnchor.constraint(equalToConstant: 184),

      tableViewTopConstraint,
      tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
      tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
      tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
    ])
  


extension TableViewScene: UITableViewDelegate 
  func scrollViewDidScroll(_ scrollView: UIScrollView) 
    let offsetY = scrollView.contentOffset.y

    headerViewOneTopConstraint.constant = max(-184, min(0, -offsetY))
    tableViewTopConstraint.constant = 184 - max(0, offsetY)
  

我也尝试将其添加到视图中

  func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) 
    let translation = scrollView.panGestureRecognizer.translation(in: scrollView.superview)

    if translation.y > 0 
      headerViewOne.transform = .init(translationX: 0, y: 184)
     else if translation.y < 0 
      headerViewOne.transform = .identity
    
  

这不起作用,而只是呈现一个黑色空间,用于在滚动到顶部时填充视图。

【问题讨论】:

你想要什么样的动画效果?你不喜欢你的 scrollViewDidScroll 实现什么? scrollViewDidScroll 工作完美,我对此非常满意,但是当用户例如在桌子的一半时,我无法将headerViewOne 重新进出视野。 headerViewOne 是一个“快速菜单”,他们应该能够通过向下拖动在列表顶部或列表中的任何位置查看它 在动画方面,只要简单的向下和向后滑动就完美了 【参考方案1】:

很难准确地说出您在寻找什么,但这可能对您有用。在这个实现中,当用户向上拖动时,标题将隐藏,当用户向下拖动时,标题将显示。无论滚动位置如何,都是如此。

我对您的一个约束进行了更改,以便将 tableView 的顶部固定到标题的底部:

    tableViewTopConstraint = tableView.topAnchor.constraint(equalTo: headerViewOne.bottomAnchor)

我也在像这样跟踪标题的状态:

enum HeaderState 
    case hidden
    case revealed
    case hiding
    case revealing


var headerState: HeaderState = .revealed

现在是滚动逻辑。如果滚动位置靠近顶部,那么我们要手动显示/隐藏标题。但是,如果滚动位置靠近底部或中心,那么我们希望为显示/隐藏功能设置动画。

func scrollViewDidScroll(_ scrollView: UIScrollView) 
    let translation = scrollView.panGestureRecognizer.translation(in: scrollView.superview)

    if scrollView.contentOffset.y < 184 
        if translation.y > 0 && headerState != .revealed && headerState != .revealing 
            headerViewOneTopConstraint.constant = max(-184, min(0, -scrollView.contentOffset.y))
         else if translation.y < 0 
            headerViewOneTopConstraint.constant = max(-184, min(0, -scrollView.contentOffset.y))
        
        return
    

    if translation.y > 0 && headerState == .hidden 

        self.headerState = .revealing
        UIView.animate(withDuration: 0.4, animations: 
            self.headerViewOneTopConstraint.constant = 0
            self.view.layoutIfNeeded()
        , completion:  _ in
            self.headerState = .revealed
        )

     else if translation.y < 0 && headerState == .revealed 

        self.headerState = .hiding
        UIView.animate(withDuration: 0.4, animations: 
            self.headerViewOneTopConstraint.constant = -184
            self.view.layoutIfNeeded()
        , completion:  _ in
            self.headerState = .hidden
        )
    

试一试,看看它是否满足您的需求。

【讨论】:

啊是的,它很完美!非常感谢,非常有帮助

以上是关于在 tableview 滚动和再次拖动 tableview 上动画 UIView 位置的主要内容,如果未能解决你的问题,请参考以下文章

使用 UIPanGesture 拖动 tableView/scrollView

heml如何让table的一部分固定另一部分可以拖动

element-ui的table组件,给某些列设置了fixed属性后,滚动条无法拖动

[Unity学习]使用ScrollRect实现自动滚动到底部显示实时消息,并在拖动的时候取消自动滚动,再次手动滑到底部,又继续自动滚动

[Unity学习]使用ScrollRect实现自动滚动到底部显示实时消息,并在拖动的时候取消自动滚动,再次手动滑到底部,又继续自动滚动

[Unity学习]使用ScrollRect实现自动滚动到底部显示实时消息,并在拖动的时候取消自动滚动,再次手动滑到底部,又继续自动滚动