kokorokun
kokorokun

Reputation: 119

UITableView Display Animation

I'm using UITableView for showing banners which shows image and title.

https://youtu.be/4CnfZLWE3VI

The youtube link shows the animation of filtering banners. When I press "fav" button, it does not animate smoothly. I'd like to have the animation smooth.

This is my swift code of UITableView.

extension HomeViewController: UITableViewDelegate, UITableViewDataSource {
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return filteredTournamentlist.count
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        if let cell = tableView.dequeueReusableCell(withIdentifier: "entryCell", for: indexPath) as? TournamentEntryCell {

            cell.usernameLabel.text = filteredTournamentlist[indexPath.row].master_info.name
            cell.titleTabel.text = self.filteredTournamentlist[indexPath.row].name
            cell.dateLabel.text = DatetimeHelper.StringFromString(
                string: self.filteredTournamentlist[indexPath.row].eventDate,
                fromFormat: DatetimeHelper.DBDateFormat,
                toFormat: DatetimeHelper.JPStringFormat
            )
            cell.gameInfoLabel.text = self.filteredTournamentlist[indexPath.row].gameName
                
            self.tournamentModel.getThumbnail(path: self.filteredTournamentlist[indexPath.row].thumbnail_path) { image in
                cell.thumbnailView.image = image
            }
            self.profileInfoModel.getIcon(path: self.filteredTournamentlist[indexPath.row].master_info.icon_path) { icon in
                cell.iconView.image = icon
            }
                
            let selectedView = UIView()
            selectedView.backgroundColor = Colors.plain
            cell.selectedBackgroundView = selectedView
            
            return cell
        }
        
        return UITableViewCell()
    }
}

It just sets some information around banner. And this↓ is a code of collectionview which shows filter buttons such as "fav" and "plan".

extension HomeViewController: UICollectionViewDataSource, UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 2
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "buttonCell", for: indexPath) as! PlainSquareButtonCollectionViewCell
        
        cell.button.setTitle(fileterButtonLabels[indexPath.row], for: .normal)
        
        let input = HomeViewModel.Input(
            getHomeTournamentsTrigger: Driver.never(),
            getUserInfo: Driver.never(),
            filter: cell.button.rx.tap
                .map { [unowned self] in
                    return self.fileterButtonLabels[indexPath.row]
                }
                .asDriverOnErrorJustComplete(),
            down: cell.rx.downButton
                .map { b in
                    return b
                }.asDriverOnErrorJustComplete()
        )
        let output = homeViewModel.transform(input: input)

        output.filteredTournamentList
        .drive(onNext: { [unowned self] tournamentList in
            self.filteredTournamentlist = tournamentList
            self.cardTableView.reloadData()
        })
        .disposed(by: disposeBag)
        
        return cell
    }
}

The tableView shows every information in filteredTournamentlist, and the content of filteredTournamentlist is changed by the filter buttons.

I don't know how to make the animation smooth... Help me!

Upvotes: 1

Views: 63

Answers (1)

Sauvik Dolui
Sauvik Dolui

Reputation: 5660

.drive(onNext: { [unowned self] tournamentList in
            self.filteredTournamentlist = tournamentList
            self.cardTableView.reloadData() // <<---------  RELOAD DATA
        })

Calling reloadData() will not give you the expected animation. What ever changes are going to happen when you tap on fav button you need to first determine and then you can apply those changes inside beginUpdates() & endUpdates() block.

It seems you have single section in the table view showing items, if so then it will be simpler for me to explain how to achieve the table view reload animation.

Step 1: Determine the changes

  1. Calculate number of rows before and after tap on fav or plan button from your data source.
  2. Determine the IndexPaths which are going to be changed (reload, add, delete).

Step 2: Apply changes on table view with animation

Apply the change inside cardTableView.beginUpdates() & cardTableView.endUpdates().

Here is sample code for that

// ONLY CONSIDERING SINGLE SECTION, CALCULTION WILL BE COMPLEX FOR MULTI SECTION TABLEVIEW


// 1. Calculation of IndexPaths which are going to be impacted
let oldCellCount = dataSource.numberOfRowsInSection(0) // Get cell count before change
let newCellCount = dataSource.numberOfRowsInSection(0) // Get cell count after the change

var indexPathsToReload: [IndexPath] = []
var indexPathsToInsert: [IndexPath] = []
var indexPathsToDelete: [IndexPath] = []

if oldCellCount > newCellCount {
    // Need to delete and reload few cells
    indexPathsToReload = (0..<newCellCount).map { IndexPath(row: $0, section: 0) }
    indexPathsToDelete = (newCellCount..<oldCellCount).map { IndexPath(row: $0, section: 0) }
} else if oldCellCount < newCellCount {
    // Need to add and reload few cells
    indexPathsToReload = (0..<oldCellCount).map { IndexPath(row: $0, section: 0) }
    indexPathsToInsert = (oldCellCount..<newCellCount).map { IndexPath(row: $0, section: 0) }
} else {
    // No change in cell count
    indexPathsToReload = (0..<newCellCount).map { IndexPath(row: $0, section: 0)}
}

// 2. Reload with animation
tableView.beginUpdates()
tableView.deleteRows(at: indexPathsToDelete, with: .none) <<--- Use your expected animation here `fade`, `right`, `top`, `left` & more
tableView.reloadRows(at: indexPathsToReload, with: .none)
tableView.insertRows(at: indexPathsToInsert, with: .none)
tableView.endUpdates()

Upvotes: 2

Related Questions