当前位置: > > > Swift - 动态添加删除TableView的单元格(以及内部元件)

Swift - 动态添加删除TableView的单元格(以及内部元件)

在Swift开发中,我们有时需要动态的添加或删除列表的单元格。
 
比如我们做一个消息提醒页面,默认页面只显示两个单元格。当点击第二个单元格(时间标签)时,下面会再添加一个单元格放置日期选择控件(同时新增单元格的高度也会变化)。而再次点击第二个单元格,日期选择控件又会隐藏。

   

1,首先创建一个静态单元格的tableViewController
将其设置成一个分区,两个单元个。并在单元格内部放置好相关组件。

2,添加其关联代码
这个 Scene 关联的代码(MyTableViewController.swift)如下。(代码已升级为Swift3)
import UIKit

class MyTableViewController: UITableViewController {
    

    @IBOutlet weak var dueDateLabel: UILabel!
    
    //日期选择器显示状态
    var datePickerVisible:Bool = false
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        self.title = "添加任务"
        //去除尾部多余的空行
        self.tableView.tableFooterView = UIView(frame:CGRect.zero)
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    //选择cell的row之后
    override func tableView(_ tableView: UITableView,
                            didSelectRowAt indexPath: IndexPath) {
        self.tableView.deselectRow(at: indexPath, animated: true)
        
        //当执行到日期选择器上一行的时候,可以判断是否要显示日期选择器了
        if indexPath.section == 0 && indexPath.row == 1{
            if !datePickerVisible{
                self.showDatePicker()
            }else{
                self.hideDatePicker()
            }
        }
        
        print(indexPath.row)
    }
    
    //显示日期选择器
    func showDatePicker(){
        //日期选择器的状态设为打开
        datePickerVisible = true
        
        let indexPathDatePicker = IndexPath(row: 2, section: 0)
        self.tableView.insertRows(at: [indexPathDatePicker],
                                  with: .automatic)
        
    }
    
    //隐藏日期选择器
    func hideDatePicker(){
        if datePickerVisible {
            //日期选择器的状态设为关闭
            datePickerVisible = false
            let indexPathDatePicker = IndexPath(row: 2, section: 0)
            self.tableView.deleteRows(at: [indexPathDatePicker],
                                      with: .fade)
        }
    }
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    //设置cell
    override func tableView(_ tableView: UITableView,
                            cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            //因为日期选择器的位置在日期显示Label下面。它的位置就是第2个section  和第3个row
            if indexPath.section == 0 && indexPath.row == 2{
                //用重用的方式获取标识为DatePickerCell的cell
                var cell = tableView.dequeueReusableCell(withIdentifier: "DatePickerCell")
                    as UITableViewCell?
                //如果没找到就创建一个
                if cell == nil {
                    //创建一个标识为DatePickerCell的cell
                    cell = UITableViewCell(style: .default,
                                           reuseIdentifier: "DatePickerCell")
                    //设置cell的样式
                    cell?.selectionStyle = .none
                    //创建日期选择器
                    let datePicker = UIDatePicker(frame: CGRect(x:0, y:0, width:320,
                                                                height:216))
                    //给日期选择器的tag
                    datePicker.tag = 100
                    //将日期选择器区域设置为中文,则选择器日期显示为中文
                    datePicker.locale = Locale(identifier: "zh_CN")
                    //将日期选择器加入cell
                    cell?.contentView.addSubview(datePicker)
                    //注意:action里面的方法名后面需要加个冒号“:”
                    datePicker.addTarget(self, action:#selector(dateChanged(_:)),
                                         for: .valueChanged)
                }
                return cell!
            }else{
                return super.tableView(tableView, cellForRowAt: indexPath)
            }
    }
    
    //日期选择器响应方法
    func dateChanged(_ datePicker: UIDatePicker){
        //更新提醒时间文本框
        let formatter = DateFormatter()
        //日期样式
        formatter.dateFormat = "yyyy年MM月dd日 HH:mm:ss"
        self.dueDateLabel.text = formatter.string(from: datePicker.date)
    }
    
    //根据日期选择器的隐藏与否决定返回的row的数量
    override func tableView(_ tableView: UITableView,
                            numberOfRowsInSection section: Int) -> Int {
        
        if section == 0  && datePickerVisible{
            return 3
        }else{
            return super.tableView(tableView, numberOfRowsInSection: section)
            
        }
    }
    
    //因为日期选择器插入后会引起cell高度的变化,所以要重新设置
    override func tableView(_ tableView: UITableView,
                            heightForRowAt indexPath: IndexPath) -> CGFloat {
        //当渲染到达日期选择器所在的cell的时候将cell的高度设为217
        if indexPath.section == 0 && indexPath.row == 2{
            return 216.0
        }else{
            return super.tableView(tableView, heightForRowAt: indexPath)
        }
    }
    
    //当覆盖了静态的cell数据源方法时需要提供一个代理方法。
    //因为数据源对新加进来的日期选择器的cell一无所知,所以要使用这个代理方法
    override func tableView(_ tableView: UITableView,
                            indentationLevelForRowAt indexPath: IndexPath) -> Int {
        if indexPath.section == 0 && indexPath.row == 2{
            //当执行到日期选择器所在的indexPath就创建一个indexPath然后强插
            let newIndexPath = IndexPath(row: 0, section: indexPath.section)
            return super.tableView(tableView, indentationLevelForRowAt: newIndexPath)
        }else{
            return super.tableView(tableView, indentationLevelForRowAt: indexPath)
        }
    }
}

3,源码下载hangge_727.zip

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作。

打赏支持
评论7
  • 7楼
    2016-06-06 10:34
    星光

    很喜欢这里的文章,使用还很清楚,思路明确,偶尔看到了,很厉害

    站长回复

    谢谢夸奖,欢迎常来看看,我会一直更新的。

  • 6楼
    2016-03-10 10:35
    Gemini

    航哥,搞定了,不用提供demo了,谢谢,要把table view的 content设置为static,就好了,麻烦了

    站长回复

    好的:)

  • 5楼
    2016-03-10 10:23
    Gemini

    航哥,请教,我用storyboard建立个新的Table View Controller,建立了新的swift文件,复制了文章内容。然后设置了Custom Class 为MyTableViewController。运行但是在模拟器是空白的,不知错在哪里。能提供个这个例子的demo吗,您费心了,谢谢!

    站长回复

    tableView要设成静态单元格

  • 4楼
    2015-12-28 16:13
    mudy

    test很不错的网站,这个demo的全部源码在哪呢,能不能提供一个下载链接呢

    站长回复

    这个demo写得挺早的,因为只有一个类,就直接粘贴在页面上了,所以就没有上传整个工程源码。

  • 3楼
    2015-12-08 15:41
    浮生若梦

    真的是太好了,偶然发现的这个网站...立马喜欢上了,看了好多,解决了我很多问题...代码很容易懂!赞

    站长回复

    谢谢你的喜欢。我会继续创作更多的文章分享给大家,欢迎常来看看。

  • 2楼
    2015-11-08 09:48
    x1911

    太喜欢这个站了,潜水很久,一直默默收藏,这个站帮了很多,代码很容易懂,支持大大,有群吗

    站长回复

    谢谢你的鼓励。群目前还没有,因为现在主要精力还是放在网站上,要不两边管理怕顾不过来。以后会考虑的。

  • 1楼
    2015-09-21 16:43
    hah

    简直赞,这就是我想要的

    站长回复

    ^_^