滑动删除 UITableView 单元格动画在 swift 2 中不起作用

Posted

技术标签:

【中文标题】滑动删除 UITableView 单元格动画在 swift 2 中不起作用【英文标题】:swipe to delete UITableView cell animation is not working in swift 2 【发布时间】:2015-10-05 14:55:35 【问题描述】:

滑动删除功能工作正常,但我无法添加动画,我尽我所能但没有任何效果。每当我添加动画代码时,删除单元格时应用程序就会崩溃。如果再次加载应用程序,会发现记录被删除,说明删除成功。

我得到的崩溃错误是:

无效更新:第 0 节中的行数无效。 更新 (1) 后包含在现有节中的行必须是 等于该节之前包含的行数 update (1),加上或减去插入或删除的行数 该部分(0 插入,1 删除)和加或减的数量 移入或移出该部分的行(0 移入,0 移出)。

我尝试的动画代码块是:

        //1
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
        //2
        tableView.deleteRowsAtIndexPaths([indexPath],
            withRowAnimation: UITableViewRowAnimation.Automatic)

我也尝试删除这些代码,但也没有用:

fetchAndSetResults() treatmentProtocolsTableView.reloadData()

swift文件中的全部代码都在这里,我把动画块注释掉了,它可以正常工作。

import UIKit
import CoreData

class Tx_Protocols: UIViewController, UITableViewDataSource, UITableViewDelegate 

    //MARK: declaratoins.
    weak var secureTextAlertAction: UIAlertAction?

    //MARK: Core data related
    var txProtocols = [TreatmentProtocolData]()
    var selectedProtocol : TreatmentProtocolData? = nil

    @IBOutlet weak var treatmentProtocolsTableView: UITableView!


    //When button + is clicked, segue show add tx VC is initiated.
    @IBAction func plusButtonAddTxProtocol(sender: AnyObject) 
        self.performSegueWithIdentifier("showAddTxVC", sender: self)
    

    override func viewDidLoad() 
        super.viewDidLoad()

        fetchAndSetResults()

        treatmentProtocolsTableView.delegate = self
        treatmentProtocolsTableView.dataSource = self
    

    //When this is used, the data shows with a slight lag, slower.
    override func viewDidAppear(animated: Bool) 
        fetchAndSetResults()
        treatmentProtocolsTableView.reloadData()
    

    //This is how you catch the app delegate core data fnxnality, GRABBING THE PROPERTY IN APP DELEGATE
    func fetchAndSetResults() 
        let app = UIApplication.sharedApplication().delegate as! AppDelegate
        let context = app.managedObjectContext
        let fetchRequest  = NSFetchRequest(entityName: "TreatmentProtocolData")

        do 
            let results = try context.executeFetchRequest(fetchRequest)
            self.txProtocols = results as! [TreatmentProtocolData]
         catch let err as NSError 
            print(err.debugDescription)
        
    



    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 
        let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier:"Cell")
        cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
        cell.textLabel!.adjustsFontSizeToFitWidth = true
        cell.textLabel!.font = UIFont.boldSystemFontOfSize(17)

        let treatmentProtocol = txProtocols[indexPath.row]
        cell.textLabel!.text = treatmentProtocol.title
        cell.imageView?.image = treatmentProtocol.getTxProtocolImage()

        return cell
    

    func numberOfSectionsInTableView(tableView: UITableView) -> Int 
        return 1
    

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

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) 
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
        self.selectedProtocol = txProtocols[indexPath.row]
        self.performSegueWithIdentifier("showTxProtocol", sender: self)


    

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) 

        if segue.identifier == "showTxProtocol" 
        let detailVC = segue.destinationViewController as! ShowTxProtocolDetailVC
        detailVC.txProtocol = self.selectedProtocol
        
    


    //MARK: Edittable table, delete button functionality.
    func tableView(tableView: UITableView,
        canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool 
            return true
    

    func tableView(tableView: UITableView,
        commitEditingStyle
        editingStyle: UITableViewCellEditingStyle,
        forRowAtIndexPath indexPath: NSIndexPath) 

            if editingStyle == UITableViewCellEditingStyle.Delete 

                let app = UIApplication.sharedApplication().delegate as! AppDelegate
                let context = app.managedObjectContext
                //1
                let protocolToRemove =
                txProtocols[indexPath.row]

                //2
                context.deleteObject(protocolToRemove)

                //3
                do 
                    try context.save()
                 catch let error as NSError 
                    print("Could not save: \(error)")
                

//                //1
//                tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
//                //2
//                tableView.deleteRowsAtIndexPaths([indexPath],
//                    withRowAnimation: UITableViewRowAnimation.Automatic)

                fetchAndSetResults()
                treatmentProtocolsTableView.reloadData()

            
    



感谢您的帮助

【问题讨论】:

【参考方案1】:

你需要封装在beginUpdates()endUpdates()里面。此外,更新用于加载表格视图的数据模型:

self.tableView.beginUpdates()
self.txProtocols.removeObjectAtIndex(indexPath.row) // Check this out 
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
self.tableView.endUpdates()

【讨论】:

谢谢 Abhinav,将“if editingstyle”代码封装在开始和结束更新中,并在您的解决方案中添加第三行代码。我不得不删除第二行。我不知道这是否是最佳做法,因为我是 swift 新手,但它工作正常。再次感谢!【参考方案2】:

根据Abhinav 接受的答案,这是我的解决方案(Swift 3)。这在我的NSFetchedResultsControllerDelegate 中实现:

func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    self.tableView.beginUpdates()


func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) 
    ...
    case .delete:
            // Delete from tableView
            removeFromSetsToDisplayByID(removeThisSet: myObject)
            tableView.deleteRows(at: [indexPath!], with: UITableViewRowAnimation.automatic)
    ...


func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) 
    self.tableView.endUpdates()

【讨论】:

以上是关于滑动删除 UITableView 单元格动画在 swift 2 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章

UITableView 禁用滑动以快速删除特定单元格

在 UITableView 单元格滑动中选择“删除”,但未调用“提交编辑样式”

iOS 7 UITableView 问题 - 当我们已经有一个单元格时尝试设置滑动以删除单元格

在 iphone sdk 中一起滑动以删除和移动 UItableView 选项中的单元格

如何制作可滑动的 UItableview 标题以显示像单元格一样的删除按钮

删除和插入具有不同高度的单元格时,UITableView 动画故障