【问题标题】:Detect when UITableView section header snaps to the top of the screen检测 UITableView 部分标题何时捕捉到屏幕顶部
【发布时间】:2017-01-16 05:47:48
【问题描述】:

我想检测UITableView 部分标题何时捕捉到屏幕顶部,然后修改标题的高度,但我不知道该怎么做。有人可以帮忙吗?

【问题讨论】:

  • 我从未实际尝试过,但也许你可以试试frame.x == 0
  • 有一个rectForHeader 方法可用于获取该部分的标题框架,然后有一个contentOffset 属性UItableView。我相信您可以计算出标题是否位于屏幕顶部。还有UIScrollViewdelegate 方法scrollViewDidScroll 可以用来检查UITableView 何时滚动
  • 非常感谢
  • 改进标题,简化解释
  • @BenOng 我建议您发表您的评论作为答案

标签: ios swift uitableview uitableviewsectionheader


【解决方案1】:

通过使用didEndDisplayingHeaderViewwillDisplayHeaderView 委托方法,我能够完成检测哪个标题卡在表格视图的顶部。这里的想法是,当我们滚动浏览表格视图的各个部分时,标题周围的行变得可见,我们可以使用tableView.indexPathsForVisibleRows 获取所有可见行的索引路径。根据我们是向上还是向下滚动,我们将屏幕上的第一个或最后一个 indexPath 与刚刚出现/消失的视图的索引路径进行比较。

//pushing up
func tableView(_ tableView: UITableView,
               didEndDisplayingHeaderView view: UIView,
               forSection section: Int) {

    //lets ensure there are visible rows.  Safety first!
    guard let pathsForVisibleRows = tableView.indexPathsForVisibleRows,
        let lastPath = pathsForVisibleRows.last else { return }

    //compare the section for the header that just disappeared to the section
    //for the bottom-most cell in the table view
    if lastPath.section >= section {
        print("the next header is stuck to the top")
    }

}

//pulling down
func tableView(_ tableView: UITableView,
               willDisplayHeaderView view: UIView,
               forSection section: Int) {

    //lets ensure there are visible rows.  Safety first!
    guard let pathsForVisibleRows = tableView.indexPathsForVisibleRows,
        let firstPath = pathsForVisibleRows.first else { return }

    //compare the section for the header that just appeared to the section
    //for the top-most cell in the table view
    if firstPath.section == section {
        print("the previous header is stuck to the top")
    }
}

【讨论】:

  • 强大而强大的解决方案!
  • 这是唯一对我有用的方法。在滚动视图中测量东西确实滚动并将矩形转换为超级视图坐标空间在快速滚动时永远不会起作用。
【解决方案2】:

我把我的评论变成了代码,它的工作原理是:

override func scrollViewDidScroll(_ scrollView: UIScrollView) {

    if scrollView == yourTableView {
        if yourTableView.rectForHeader(inSection: <#sectionIWant#>).origin.y <= tableView.contentOffset.y-defaultOffSet.y &&
            yourTableView.rectForHeader(inSection: <#sectionIWant#>+1).origin.y > tableView.contentOffset.y-defaultOffSet.y {
            print("Section Header I want is at top")
        }
    } else {
        //Handle other scrollViews here
    }
}

因此,您将 sectionIWant 替换为 Int,当该部分的标题位于顶部时,print 将运行。请注意,yourTableView 不是 scrollViewDidScroll 的参数,因此您必须保留引用到您的UITableView 其他地方并在此处使用它。

或者,如果您想不断更新您可以使用哪个部分标题位于顶部:

override func scrollViewDidScroll(_ scrollView: UIScrollView) {

    if scrollView == yourTableView {
        var currentSection = 0
        while !(tableView.rectForHeader(inSection: currentSection).origin.y <= (tableView.contentOffset.y-defaultOffSet.y) &&
            tableView.rectForHeader(inSection: currentSection+1).origin.y > (tableView.contentOffset.y)-defaultOffSet.y) {
                if tableView.contentOffset.y <= tableView.rectForHeader(inSection: 0).origin.y {
                    break   //Handle tableView header - if any
                }
                currentSection+=1
                if currentSection > tableView.numberOfSections-2 {
                    break   //Handle last section
                }
        }
        print(currentSection)
    }

}

请注意,在这两个代码中都有一个defaultOffSet,它是加载时tableViewcontentOffSet,这是为了考虑到contentOffSet 在某些情况下不会从0 开始 - 我是不知道是什么时候,但我确实遇到过这种情况。

【讨论】:

  • 其实UITableView是UIScrollView的一个子类,所以传入的scrollView可以投到你的table view类guard let tableView = scrollView as? UITableView else { return }
  • 同意,但在大多数情况下,表格视图已经是一个 IBOutlet,因此您可以使用它而不是添加另一行来投射滚动视图,但我想添加一个检查以确保表格视图是实际上应该完成一个滚动而不是另一个滚动视图......我稍后会更新我的答案
【解决方案3】:

这个解决方案对我有用。

func scrollViewDidScroll(_ scrollView: UIScrollView) {
  self.visibleHeaders.forEach { header in
    let headerOriginalFrame = self.myTableView.rectForHeader(inSection: header.tag)
    let headerCurrentFrame = header.frame
    let fixed = headerOriginalFrame != headerCurrentFrame
    // Do things you want
  }
}

这里是完整的源代码。 https://github.com/jongwonwoo/CodeSamples/blob/master/TableView/TableviewFixedHeader/Tableview/ViewController.swift

【讨论】:

    【解决方案4】:

    事实证明,我对这个问题的解决方案非常有效且用途广泛。如果这对某人有帮助,我会很高兴

    func scrollViewDidScroll(_ scrollView: UIScrollView) {
    let sectionPosition = tableView.rect(forSection: sectionIndex)
    let translation = scrollView.panGestureRecognizer.translation(in: scrollView.superview)
    
    if let dataSource = dataSource,
       scrollView.contentOffset.y >= sectionPosition.minY {
    
    //Next section
    
        guard dataSource.count - 1 > sectionIndex else { return }
        sectionIndex += 1
    } else if translation.y > 0,
              scrollView.contentOffset.y <= sectionPosition.minY {
    
    //Last section
    
        guard sectionIndex > 0 else { return }
        sectionIndex -= 1
    }
    

    【讨论】:

      【解决方案5】:

      聚会迟到了,但查看所有回复并没有解决我的问题。

      下面的做法,各取一点,同时加入,比较通用,不固定的做法。

          override func scrollViewDidScroll(_ scrollView: UIScrollView) {
              guard let visibleIndexs = self.tableView.indexPathsForVisibleRows,
                    !visibleIndexs.isEmpty else { return }
              
              var visibleHeaders = [Int]()
              visibleIndexs.forEach { anIndexPath in
                  if !visibleHeaders.contains(anIndexPath.section) {
                      visibleHeaders.append(anIndexPath.section)
                  }
              }
              
              visibleHeaders.forEach { header in
                  let headerView = tableView.headerView(forSection: header)
                  let headerOriginalFrame = self.tableView.rectForHeader(inSection: header)
                  if headerOriginalFrame != headerView?.frame {
          //do something with top headerView
                  } else {
          //do something else with all the others headerView(s)
                  }
              }
          }
      
      

      【讨论】:

        猜你喜欢
        • 2018-07-04
        • 1970-01-01
        • 2017-10-29
        • 1970-01-01
        • 2012-02-15
        • 2020-12-13
        • 1970-01-01
        • 2021-09-28
        • 1970-01-01
        相关资源
        最近更新 更多