简体   繁体   English

"检测 UITableView 部分标题何时捕捉到屏幕顶部"

[英]Detect when UITableView section header snaps to the top of the screen

I want to detect when the UITableView section header snaps on top of the screen and then modify header's height, but I have no idea how to do that.我想检测UITableView部分标题何时捕捉到屏幕顶部,然后修改标题的高度,但我不知道该怎么做。 Can anyone help?任何人都可以帮忙吗?

I was able to accomplish detecting which header is stuck to top of the table view by using the didEndDisplayingHeaderView and willDisplayHeaderView delegate methods.通过使用didEndDisplayingHeaderViewwillDisplayHeaderView委托方法,我能够完成检测哪个标题卡在表格视图的顶部。 The idea here is that the while we are scrolling through the sections of the table view, the rows around the header are becoming visible and we can grab the index paths of all visible rows using tableView.indexPathsForVisibleRows .这里的想法是,当我们滚动表格视图的各个部分时,标题周围的行变得可见,我们可以使用tableView.indexPathsForVisibleRows获取所有可见行的索引路径。 Depending on if we are scrolling up or down, we compare the first or last indexPath on screen to the index path of the view that just appeared/disappeared.根据我们是向上还是向下滚动,我们将屏幕上的第一个或最后一个 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")
    }
}

I went to make my comment into codes and it works like:我去把我的评论变成代码,它的工作原理如下:

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
    }
}

So you replace sectionIWant with an Int and when that section's header is at top, the print will run.Note that yourTableView is not a parameter of scrollViewDidScroll so you have to keep a reference to your UITableView elsewhere and use it here.所以,你替换sectionIWantInt ,当该节的头是在顶部时, print将run.Note是yourTableView不是参数scrollViewDidScroll所以你必须参考存到自己UITableView的其他地方,并在这里使用它。

Alternatively if you want to be constantly updated on which section header is at top you can use:或者,如果您想不断更新哪个部分标题位于顶部,您可以使用:

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)
    }

}

Note that in both codes there is a defaultOffSet which is the contentOffSet of the tableView on load, this is to take into account that the contentOffSet does not start at 0 in some situations - I am not sure when but I do encounter such cases before.请注意,在两个代码中都有一个defaultOffSet ,它是加载时tableViewcontentOffSet ,这是考虑到contentOffSet在某些情况下不会从 0 开始 - 我不确定何时但我之前确实遇到过这种情况。

This solution works for me.这个解决方案对我有用。

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
  }
}

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

My solution to this problem turned out to be really working and versatile enough.事实证明,我对这个问题的解决方案确实有效且用途广泛。 I would be very glad if this helps someone如果这对某人有帮助,我会很高兴

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
}

Late to the party, but reviewing up all responses didn't solve my issue.派对迟到了,但查看所有回复并没有解决我的问题。

The following approach, borrow a little bit from each one, adding at the same time, a more general and not fixed approach.下面的做法,每一个都借鉴了一点,同时又增加了一个更通用且不固定的做法。

    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)
            }
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM