在 UICollectionView 或 UITableView 中实现 Sticky Cell [英] Implementing Sticky Cell in UICollectionView or UITableView

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

问题描述

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

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 中实现 Sticky Cell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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