从 UITableView 中删除自定义视图

Posted

技术标签:

【中文标题】从 UITableView 中删除自定义视图【英文标题】:Deleting a custom view from UITableView 【发布时间】:2018-07-05 06:05:10 【问题描述】:

我正在向左滑动以删除 Swift 3 中的自定义视图单元格。

单元格是:

class CustomTableCell: SwipeTableViewCell

    public var atest = UILabel();
    public var btest = UILabel();

    var animator: Any?

    override init(style: UITableViewCellStyle, reuseIdentifier: String!)
    
        super.init(style: style, reuseIdentifier: reuseIdentifier);

        let height = 140;

        atest = UILabel(frame: CGRect(x: 20 + (activityWidth / 2), y: 72, width: (activityWidth / 2) - 10, height: 30));

        btest = UILabel(frame: CGRect(x: 20 + (activityWidth / 2), y: 102, width: (activityWidth / 2) - 10, height: 30));

        self.contentView.addSubview(atest);
        self.contentView.addSubview(btest);
    

然后在我的表格视图控制器中,我有:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell

    let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier") as! CustomTableCell;

    cell.atest.text = "text from an array at indexpath.row";
    cell.btest.text = "another different text from an array";

    return cell;

表格视图控制器中的删除发生在这里:

func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]?

    let delete = SwipeAction(style: .destructive, title: "Delete")
    
        action, indexPath in
        print("delete button tapped");

        // self.table.deleteRows(at: [indexPath], with: .none);

        // database is a string index array
        self.database.remove(at: indexPath.row);

        if (self.database.count == 0)
        
            self.noText.isHidden = false;
            self.footer.isHidden = false;

            self.table.tableFooterView = self.footer;
        

        // self.table.setNeedsDisplay();
    

    delete.backgroundColor = UIColor.red;

    return [delete];

我通过向左滑动进行删除,它会正确删除所有内容。我遇到的问题是删除使折叠下的所有表格视图单元格与最后一个可见单元格相同。

我该如何解决这个问题?我也在使用自定义单元格视图。

一个例子是我有 6 行,前 4 行是可见的。删除第一行使第 4 行和第 5 行相同。如在最后一个可见行也成为第一个不可见行。 prepareForReuse 可能无法正常工作。

删除有效,从 6 行变为 5 行,但下面是一个示例。

 UITableView
 First row label         A
 Second row label        B
 Third row label         C
 Fourth row label        D (last visible row)
 Fifth row label         E (first non visible row)
 Sixth row label         F

通过滑动删除第一行会创建这个新的 UITableView:

 UITableView
 Second row label        B
 Third row label         C
 Fourth row label        D
 Fourth row label        D (last visible row)
 Fifth row label         E (first non visible row)

可重复使用的单元格无法正常工作。

我不使用 awakeFromNib,也刚升级到 swift 4.1。

【问题讨论】:

使用处理删除的代码更新您的问题。 我更新了删除,用github.com/SwipeCellKit/SwipeCellKit处理刷屏 不相关但你为什么不在Interface Builder中设计单元格?这就是 Swift:if 条件周围没有尾随分号和括号。 当您删除/移除单元格时,自定义单元格视图会随之消失。 我遇到的问题是删除使折叠下的所有表格视图单元格与最后一个可见单元格相同是什么意思?可以分享截图吗? 它们是屏幕下方的行,直到滚动到它们才能看到 【参考方案1】:

TableView 自定义单元格中,如果您从storyboardXIB 添加views,那么它会在滚动时被删除,但如果您以编程方式添加views,那么您必须从@987654327 中删除视图@:

cellForRow 中使用以下代码:

for label in cell.subviews 
    if let mylabel = label as? UILabel 
        mylabel.removeFromSuperview()
    

或者您可以在prepareForReuse 方法中使用此代码customCellClass

class myCustomCell: UITableViewCell 

    override func prepareForReuse() 
        super.prepareForReuse()
        for view in self.subviews 
            view.removeFromSuperview()
        
    

    override func awakeFromNib() 
        super.awakeFromNib()
        // Initialization code
    


以上代码将从单元格中删除所有子视图。

查看以下链接以获得更多答案:

remove the subviews from the contentView of UITableViewCell (reset the UITableView)

编辑

我在tableView 中使用字符串ArrayswipeDelete 功能尝试了以下代码:

class ViewController: UIViewController 

    @IBOutlet weak var sampleTableView: UITableView!

    var nameArray = ["Snoop", "Sarah", "Fido", "Mark", "Jill", "Parague", "London", "Barcelona", "Italy", "France", "Eiffiel", "Tower", "Paris", "Europe", "Amsterdam", "Zurich", "Germany", "Munich", "Milan", "Venice", "Switzerland", "Brussels"]

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    


extension ViewController: UITableViewDataSource, UITableViewDelegate 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return nameArray.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)

        cell.textLabel?.text = nameArray[indexPath.row] + " - " + String(describing: indexPath.row)

        return cell
    

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool 
        return true
    

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) 
        if (editingStyle == UITableViewCellEditingStyle.delete) 
            // handle delete (by removing the data from your array and updating the tableview)
            tableView.beginUpdates()
            nameArray.remove(at: indexPath.row)
            tableView.deleteRows(at: [indexPath], with: .automatic)
            tableView.endUpdates()
        
    

当我开始滑动删除 tableView 单元格时,string 数据是正确的,但 indexPath 值不会改变。当我滚动tableView 时,它会发生变化。这在逻辑上是正确的,因为删除后字符串数据索引已更改,并且当重新使用单元格时,新索引将可见。

使用 SwipwCellKit 进行编辑:

使用与SwipeCellKit 相同的代码:

我的ViewController

class ViewController: UIViewController 

    @IBOutlet weak var sampleTableView: UITableView!

    var nameArray = ["Snoop", "Sarah", "Fido", "Mark", "Jill", "Parague", "London", "Barcelona", "Italy", "France", "Eiffiel", "Tower", "Paris", "Europe", "Amsterdam", "Zurich", "Germany", "Munich", "Milan", "Venice", "Switzerland", "Brussels"]

    override func viewDidLoad() 
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    


extension ViewController : UITableViewDataSource, UITableViewDelegate, SwipeTableViewCellDelegate 

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
        return 72
    

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return nameArray.count
    

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier") as! CustomTableCell

        cell.delegate = self

        cell.atest.text = nameArray[indexPath.row] + " - " + String(describing: indexPath.row)
        cell.btest.text = "another different text from an array";

        return cell;
    

    func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> [SwipeAction]?
    
        let delete = SwipeAction(style: .destructive, title: "Delete")
        
            action, indexPath in
            print("delete button tapped")

            self.nameArray.remove(at: indexPath.row)

            self.sampleTableView.deleteRows(at: [indexPath], with: .none)
        

        delete.backgroundColor = UIColor.red;

        return [delete];
    

我的CustomTableViewCell

class CustomTableCell: SwipeTableViewCell 

    public var atest = UILabel()
    public var btest = UILabel()

    var animator: Any?

    override func awakeFromNib() 
        atest = UILabel(frame: CGRect(x: 20 , y: 2, width: 200, height: 30));

        btest = UILabel(frame: CGRect(x: 20 , y: 32, width: 200, height: 30));

        self.contentView.addSubview(atest);
        self.contentView.addSubview(btest);
    


它的工作方式与第一次编辑相同。

编辑

CustomTableViewCell 使用 init

class CustomTableViewCell: SwipeTableViewCell 

    public var atest = UILabel();
    public var btest = UILabel();

    var animator: Any?

    override init(style: UITableViewCellStyle, reuseIdentifier: String!)
    
        super.init(style: style, reuseIdentifier: reuseIdentifier)


        atest = UILabel(frame: CGRect(x: 20 , y: 2, width: 100, height: 30))

        btest = UILabel(frame: CGRect(x: 20 , y: 32, width: 100, height: 30))

        self.contentView.addSubview(atest)
        self.contentView.addSubview(btest)
    

    required init?(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)
        fatalError("init(coder:) has not been implemented")
    

更改cellForRow:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = CustomTableViewCell.init(style: .default, reuseIdentifier: "reuseIdentifier")

    cell.delegate = self

    cell.atest.text = nameArray[indexPath.row] + " - " + String(describing: indexPath.row)
    cell.btest.text = "another different text from an array";

    return cell;

仍然和上面一样工作。

【讨论】:

如果我要删除一个 uiview 和 5 个 uilabels 怎么办?我把它放在cellforrowat的顶部吗?我可以获得第二个的完整示例吗?非常感谢 这行为非常奇怪并且造成更大的伤害。我有 4 行可见,2 行在折叠下方,我可以正确删除第一行,但第 4 行仍然成为第 5 行。这是一个重用问题。 我没有得到什么伤害。所有的细胞都是一样的,对吧?细胞计数正在减少? 4 行可见,2 行在首屏下方。当您删除第一个时,还可以看到 4 行,并且 1 位于折叠下方? 它会删除所有内容。顺便说一句,我用示例代码更新了问题。 我正在使用问题中提到的刷卡插件【参考方案2】:

问题在于您的细胞是如何被重复使用的。将这行代码添加到表格单元格类中:

  override func prepareForReuse() 
    super.prepareForReuse()

        atest.text = nil
        btest.text = nil
  

【讨论】:

y 代码 sigaborts 在 let delete 大括号结束时。它运行delete,进入init的customcell类,运行cellForRowAt返回delete并在delete函数结束时崩溃——cdub 14 hours a 我也需要 deleteatrows 吗?我在下面的答案中尝试使用从子视图中删除的方式准备ForReuse,但这并没有奏效,它只是删除了所有内容 感谢您的帮助 你的删除函数正在被你的 tableViewDelegate 删除函数调用,对吧?我看不到您实际上在哪里告诉您的 tableView 删除单元格。我只看到您正在更改 dataSource 数组“数据库”。您实际上需要在 tableView 委托或自定义删除函数中告诉 tableView 删除其中一个单元格。看起来您已经注释掉了该代码。 从我认为插件处理它的删除返回后它是 sigabrting

以上是关于从 UITableView 中删除自定义视图的主要内容,如果未能解决你的问题,请参考以下文章

在 UITableView 上延迟 reloadData

UITableView 自定义单元格按钮从主视图中选择其他按钮?

从 UITableView 中删除以编程方式自定义的 UITableViewCell 时约束中断

UITableView自定义单元格按钮从主视图中选择其他按钮?

自定义 UITableView 部分标题视图正在破坏

如何在带有标题视图和 UITableview 的自定义视图中正确设置 UISearchbar 的动画?