arun siva
arun siva

Reputation: 869

How to collapse tableview with animation?

I have a tableview with two sections.

var categories = ["a", "b", "c"]
var items = ["1" , "2", "3"]//will be different based on category selection
var selectedCategory: String?

Initially first section only visible. After the user selects any row in 0th section section 1 will have 3 rows and section 0 will have only selected row.

For ex. if category "b" is selected "a","c" rows should be removed and "1","2","3" rows should be added.

Now if the "b" is deselected "a","c" rows should be added and "1","2","3" rows should be removed.

//UITableViewDataSource

func numberOfSections(in tableView: UITableView) -> Int {
    return selectedCategory == nil ? 1 : 2
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return section == 0 ? categories.count : items.count
}

I've done this using tableView.reloadData(). It does't show any animation. I'm trying to achieve this using the following methods

tableView.deleteRows(at: [IndexPath], with: UITableViewRowAnimation)
tableView.insertRows(at: [IndexPath], with: UITableViewRowAnimation)

I'm struggling to get indexpaths to insert and delete

Upvotes: 0

Views: 221

Answers (2)

D. Mika
D. Mika

Reputation: 2808

You need to wrap the deleteRows and insertRows call in tableView.beginUpdates and tableView.endUpdates.

https://developer.apple.com/documentation/uikit/uitableview/1614908-beginupdates?language=objc

Or use performBatchUpdates:completion:.

https://developer.apple.com/documentation/uikit/uitableview/2887515-performbatchupdates?language=objc

Edit

Ok, let me explain some things in detail. :-)

First I think you need to modify numberOfRowsInSection, because you said section 0 should show all categories as long as none is selected and after selecting one, it should display only that one row.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    switch section {
    case 0:
        // If no category is selected, we display all categories, otherwise only the selected one.
        return selectedCategory == nil ? categories.count : 1
    case 1:
        return items.count
    default:
        return 0
    }
}

Second, this is an example of how didSelectRowAt could look like. I changed selectedCategory to Int? to store the index of the selected category and not its name. As you can see, in section 0 the rows that are not the selected category are deleted, while section 1 is added completely, as it did not exist before.

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    if selectedCategory == nil {
        // Save index on selected category
        selectedCategory = indexPath.row

        // set items array
        …

        // Animate change
        var indexPaths = [IndexPath]()
        for (index, _) in categories.enumerated() {
            if index != selectedCategory {
                indexPaths.append(IndexPath(row: index, section: 0))
            }
        }

        tableView.performBatchUpdates({
            // delete rows from section 0
            tableView.deleteRows(at: indexPaths, with: .automatic)
            // insert section 1
            tableView.insertSections(IndexSet(integer: 1), with: .automatic)
        }, completion: nil)
    }
}

Upvotes: 1

Manish_Nainwal
Manish_Nainwal

Reputation: 301

instead of reload whole tableView do this:-

tableView.beginUpdates()
tableView.deleteRows(at: [IndexPath], with: UITableViewRowAnimation.top)
tableView.insertRows(at: [IndexPath], with: UITableViewRowAnimation.top)
tableView.endUpdates()

Upvotes: 1

Related Questions