Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UITableView Scrolls to top after insert row

I have an expandable UITableView. When sections tapped, they expand or collapse with animation (Scroll). My problem is that there is a weird animation when expanding or collapsing headers. UITableView scrolls to top and then goes to the tapped cell. In addition, when there is no expanded cell, sometimes, It doesn't scroll to top and there is a big space between top header and top view of UITableView.

My problem is that I need to scroll to expanded section and also get rid of scroll to top bug.

I tried below solution but didn't work for me: prevent table view to scrolling top after insertRows

It also looks like same problem with below question, but can't figure out how to implement it. Why does my UITableView "jump" when inserting or removing a row?

How I toggle selection:

func toggleSection(header: DistrictTableViewHeader, section: Int) {
    print("Trying to expand and close section...")
    // Close the section first by deleting the rows
    var indexPaths = [IndexPath]()
    for row in self.cities[section].districts.indices {
        print(0, row)
        let indexPath = IndexPath(row: row, section: section)
        indexPaths.append(indexPath)
    }

    let isExpanded = self.cities[section].isExpanded
    if(isExpanded){
        AnalyticsManager.instance.logPageEvent(screenName: analyticsName!, category: "Button", action: Actions.interaction, label: "\(self.cities[section].name) Collapse Click")
    }else{
        AnalyticsManager.instance.logPageEvent(screenName: analyticsName!, category: "Button", action: Actions.interaction, label: "\(self.cities[section].name) Expand Click")
    }
    self.cities[section].isExpanded = !isExpanded

    // This call opens CATransaction context
    CATransaction.begin()
    // This call begins tableView updates (not really needed if you only make one insertion call, or one deletion call, but in this example we do both)
    tableView.beginUpdates()
    if isExpanded {

        tableView.deleteRows(at: indexPaths, with: .automatic)
    } else {
        tableView.insertRows(at: indexPaths, with: .automatic)
    }
    // completionBlock will be called after rows insertion/deletion animation is done
    CATransaction.setCompletionBlock({
        // This call will scroll tableView to the top of the 'section' ('section' should have value of the folded/unfolded section's index)
            if !isExpanded{
                self.tableView.scrollToRow(at: IndexPath(row: NSNotFound, section: section) /* you can pass NSNotFound to scroll to the top of the section even if that section has 0 rows */, at: .top, animated: true)
            }
    })

    if self.scrollToTop(){
        self.tableView.setContentOffset(.zero, animated: true)
    }
    // End table view updates
    tableView.endUpdates()


    // Close CATransaction context
    CATransaction.commit()

}

private func scrollToTop() -> Bool{
    for sec in self.cities{
        if(sec.isExpanded){
            return false
        }
    }
    return true
}

I'm giving height of cell inside;

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 120
}

How I declare headers;

func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {

    let header = DistrictTableViewHeader()
    header.isColapsed = !self.cities[section].isExpanded
    header.customInit(title: self.cities[section].name, section: section, delegate: self)
    return header
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
    return 60
}

EDIT: Solution in this question (Setting estimated height to 0) looks like working when inserting row. However, I still have bug when deleting rows. Bottom header goes to center of tableview and then goes to bottom after collapse header.

iOS 11 Floating TableView Header

like image 862
Emre Önder Avatar asked Nov 08 '22 01:11

Emre Önder


1 Answers

You can try using below code. Just get the last content offset of your tableview. Then do the update and reassign the content offset.

let lastOffset = tableView.contentOffset
self.tableView.beginUpdates()
self.tableView.layer.removeAllAnimations()
self.tableView.endUpdates()
tableView.contentOffset = lastOffset
like image 196
Hardik Halani Avatar answered Nov 14 '22 22:11

Hardik Halani