在UICollectionView或UITableView中实现粘性单元格 [英] Implementing Sticky Cell in UICollectionView or UITableView

查看:129
本文介绍了在UICollectionView或UITableView中实现粘性单元格的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要实现一个带有项目列表的表格,其中包括一个应该始终显示在屏幕上的项目.因此,例如:

I am to implement a table with a list of items which includes one item that should always be onscreen. So, for example:

  • 列表中有50个项目
  • 您的粘性"列表项是第25个
  • 您有10个项目可能一次显示在屏幕上
  • 尽管您在列表中的位置,列表应始终保持可见
  • 如果您的商品低于列表中的位置,它将显示在列表的底部
  • 如果您的商品在以前的商品之间,则应显示在列表顶部
  • 一旦您到达列表中的项目的实际位置,它就会与列表的滚动一起移动

下面的插图可以更好地理解实施要求:

Here are the illustrations to better understand the implementation requirements:

对于可能如何实现的任何想法,建议或建议将感到高兴.不幸的是,我找不到任何有用的库或解决方案来解决此问题.在这种情况下,UICollectionView和UITableView都是可以接受的.

Will be glad for any possible ideas, suggestions or recommendations on how can this possibly implemented. Unfortunately, I failed to find any useful libraries or solutions that solve this problem. UICollectionView and UITableView are both acceptable for this case.

根据我的理解,粘滞的页眉或页脚在这种情况下不起作用,因为它们仅覆盖了我所需功能的一半.

Sticky header or footer, as per my understanding do not work in this case as they cover only half of the functionality that I need.

预先感谢您的评论和答案!

Thank you in advance for your comments and answers!!!

推荐答案

我很确定您实际上不能像这样使同一单元格变得很粘.但是,您可以通过自动布局技巧来产生粘性的错觉.基本上,我的建议是,您可以拥有与您要保持粘性"状态的单元格相同的视图.并在可见黏性细胞的同时将它们约束在黏性细胞的顶部.如果您缓慢滚动,则我能做到的最好的效果看起来并不十分完美.(粘性单元在移至顶部或底部位置之前,大部分会从屏幕上移开.我认为在相当正常的滚动速度下它并不明显.您的行驶距离可能会有所不同.)

I'm pretty sure you can't actually have the same actual cell be sticky like that. You can create the illusion of stickiness through auto layout trickery though. Basically, my suggestion is that you can have views that are the same as your cells that you want to be "sticky" and constrain them on top of your sticky cells while your sticky cells are visible. The best I could pull off on this doesn't look quite perfect if you scroll slowly. (The sticky cell goes mostly off screen before snapping to the top or bottom position. It isn't noticeable in my opinion at fairly normal scrolling speeds. Your mileage may vary.)

关键是设置一个表格视图委托,以便您可以通知该单元何时出现在屏幕上或不出现在屏幕上.

The key is setting up a table view delegate so you can get notified about when the cell will or will not be on the screen.

我提供了一个示例视图控制器.我敢肯定我的示例代码在某些地方不起作用.(例如,我不处理堆叠多个粘性"单元格或动态行高的情况.此外,我将粘性单元格设置为蓝色,这样更容易看到粘性.)

I've included an example view controller. I'm sure there are areas where my example code won't work. (For example, I didn't handle stacking multiple "sticky" cells, or dynamic row heights. Also, I made my sticky cell blue so it would be easier to see the stickiness.)

为了运行示例代码,如果您创建新的UIKit应用程序,则应该只需将其粘贴到Xcode生成的默认项目中即可.只需将他们给您的视图控制器替换为该视图控制器,即可对其进行操作.

In order to run the example code, you should just be able to paste it into a default project Xcode generates if you create a new UIKit app. Just replace the view controller they gave you with this one to see it in action.

import UIKit

struct StickyView {
    let view: UIView
    let constraint: NSLayoutConstraint
}

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    lazy var stickyViewConstraints = [Int: StickyView]()
    
    lazy var tableView: UITableView = {
        let table = UITableView()
        table.translatesAutoresizingMaskIntoConstraints = false
        table.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        table.rowHeight = 40
        table.dataSource = self
        table.delegate = self
        return table
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        addTable()
        setupStickyViews()
    }
    
    private func addTable() {
        view.addSubview(tableView)
        tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
        tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
        tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    }
    
    private func setupStickyViews() {
        let cell25 = UITableViewCell()
        cell25.translatesAutoresizingMaskIntoConstraints = false
        cell25.backgroundColor = .blue
        cell25.textLabel?.text = "25"
        view.addSubview(cell25)
        cell25.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
        cell25.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
        cell25.heightAnchor.constraint(equalToConstant: tableView.rowHeight).isActive = true
        
        let bottom = cell25.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
        bottom.isActive = true
        stickyViewConstraints[25] = StickyView(view: cell25, constraint: bottom)
    }

    // MARK: - Data Source
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return section == 0 ? 50 : 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        cell.textLabel?.text = "\(indexPath.row)"
        return cell
    }
    
    // MARK: - Delegate
    func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        guard let stickyView = stickyViewConstraints[indexPath.row] else { return }
        stickyView.constraint.isActive = false
        var verticalConstraint: NSLayoutConstraint
        if shouldPlaceStickyViewAtTop(stickyRow: indexPath.row) {
            verticalConstraint = stickyView.view.topAnchor.constraint(equalTo: view.topAnchor)
        } else {
            verticalConstraint = stickyView.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        }
        verticalConstraint.isActive = true
        stickyViewConstraints[indexPath.row] = StickyView(view: stickyView.view, constraint: verticalConstraint)
    }
    
    private func shouldPlaceStickyViewAtTop(stickyRow: Int) -> Bool {
        let visibleRows = tableView.indexPathsForVisibleRows?.map(\.row)
        guard let min = visibleRows?.min() else { return false }
        return min > stickyRow
    }
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        if let stickyView = stickyViewConstraints[indexPath.row] {
            stickyView.constraint.isActive = false
            let bottom = stickyView.view.bottomAnchor.constraint(equalTo: cell.bottomAnchor)
            bottom.isActive = true
            stickyViewConstraints[indexPath.row] = StickyView(view: stickyView.view, constraint: bottom)
        }
    }
}

这篇关于在UICollectionView或UITableView中实现粘性单元格的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆