当前位置: > > > Swift - 实现tableView静态单元格与动态单元格混合使用(附样例)

Swift - 实现tableView静态单元格与动态单元格混合使用(附样例)

使用表格(UITableView)时,我们可以选择其采用静态单元格(Static Cell)还是动态单元格(Dynamic Cell)。前者使用方便,只需要在 storyboard 中设置好各个单元格即可。后者使用灵活,可以根据绑定的数据动态创建对应的单元格并显示。
但这二者并不是互斥的,我们可以在同一个 tableView 混合使用它们。比如部分单元格使用动态的,部分单元格使用静态的。下面通过一个样例作为演示。

1,样例效果图
(1)下面是一 wifi 选择页面。单元格一共分为三个 section
(2)第1个、第3个 section 里的单元格都是固定的,所以我们可以使用 Static Cell
(3)中间 section 里的单元格是根据 wifi 列表数据来动态显示的,所以使用 Dynamic Cell

2,实现步骤
(1)在 Main.storyboard 中添加一个 table view controller。作为演示,这里勾选“Is Initial View Controller”将其作为初始页面。

(2)将 table view Content 改成 Static CellsSections 改成 3

(3)由于第1个、第3个的分组里的 cell 都是不变的。所以我们这里直接配置好它们内部的组件。

(4)而第2个分组里的单元格是动态的,这里就将其 Rows 设为1。
 

(5)创建一个自定义类 TableViewController(继承自 UITableViewController)。将场景中的 TableViewController 与新建这个新建类进行绑定。

(6)TableViewController.swift 代码如下:
import UIKit

class TableViewController: UITableViewController {
    
    //wifi数据集合
    let wifiArray = ["hangge-wifi-1","hangge-wifi-2","hangge-wifi-3"]

    override func viewDidLoad() {
        super.viewDidLoad()

        //创建一个重用的单元格
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "wifiCell")
        //去除尾部多余的空行
        self.tableView.tableFooterView = UIView(frame:CGRect.zero)
        //设置分区头部字体颜色和大小
        UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self])
            .textColor = UIColor.gray
        UILabel.appearance(whenContainedInInstancesOf: [UITableViewHeaderFooterView.self])
            .font = UIFont.systemFont(ofSize: 13.0, weight: UIFontWeightMedium)
    }
    
    //返回分区数
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 3
    }

    //返回每个分区中单元格的数量
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int)
        -> Int {
        if section == 1 {
            return wifiArray.count
        }else{
            return 1
        }
    }

    //设置cell
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
        //只有第二个分区是动态的,其它默认
        if indexPath.section == 1 {
            //用重用的方式获取标识为wifiCell的cell
            let cell = tableView.dequeueReusableCell(withIdentifier: "wifiCell",
                                                     for: indexPath)
            cell.textLabel?.text = wifiArray[indexPath.row]
            return cell
        }else{
            return super.tableView(tableView, cellForRowAt: indexPath)
        }
    }
    
    //因为第二个分区单元格动态添加,会引起cell高度的变化,所以要重新设置
    override func tableView(_ tableView: UITableView,
                            heightForRowAt indexPath: IndexPath) -> CGFloat {
        if indexPath.section == 1{
            return 44
        }else{
            return super.tableView(tableView, heightForRowAt: indexPath)
        }
    }
    
    //当覆盖了静态的cell数据源方法时需要提供一个代理方法。
    //因为数据源对新加进来的cell一无所知,所以要使用这个代理方法
    override func tableView(_ tableView: UITableView,
                            indentationLevelForRowAt indexPath: IndexPath) -> Int {
        if indexPath.section == 1{
            //当执行到日期选择器所在的indexPath就创建一个indexPath然后强插
            let newIndexPath = IndexPath(row: 0, section: indexPath.section)
            return super.tableView(tableView, indentationLevelForRowAt: newIndexPath)
        }else{
            return super.tableView(tableView, indentationLevelForRowAt: indexPath)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
源码下载hangge_1387.zip

关于动态添加、移除单元格,还可以参考我的另一篇文章:Swift - 动态添加删除TableView的单元格(以及内部元件)
评论3
  • 3楼
    2018-01-13 13:48
    小豪

    站长,请问中间那个动态单元格能自定义多行显示吗? 毕竟不同情况要求不一样。

    站长回复

    可以的,只要把单元格label的numberOfLines设置成你想显示的行数就可以了。

    比如:cell.textLabel?.numberOfLines = 2 则显示两行文字
    或者:cell.textLabel?.numberOfLines = 0 则不限制行数,有几行就自动显示几行

  • 2楼
    2018-01-12 11:13
    小豪

    站长,为什么设置cell里面的indexPath.row有些程序运行运行没问题 有些程序报错
    Thread1:Fatal error: Unexpectedly found nil while unwrapping an optional value
    这个错的,求解!!!

    站长回复

    不太明白你的意思,是我样例又问题吗?

  • 1楼
    2017-10-31 14:59
    skychf

    你的是 self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "wifiCell") 。 能不能直接用界面上的那个单元格。 我用了好像一直报错

    站长回复

    确实不可以,如果把将table view的Content设为Static Cells的话就不行了。