UITableView Reload Rows unnaturally jerking the TableView in iOS 11.2
Asked Answered
T

4

5

Strange issue arrived after updating new XCODE 9.2 with iOS 11.2, by calling

let indexPath = IndexPath(item: 0, section: 1)
self.tableViewHome.reloadRows(at: [indexPath], with: .none)

It causes unnecessary jerking the whole TableView, Prior it was very fine with these code.

GIF Image for iOS 11.2

enter image description here

GIF Image for iOS 11.1

enter image description here

How to stop this Jerking, I have to reload only one cell in the tableview among two cells.

Any help will be appreciated.

Thanks

Tenor answered 7/12, 2017 at 8:9 Comment(8)
I don't think its due to iOS 11. In cellForRow you must be adding or removing views from cell view. That is generally the reason for jerks.Adey
@Mohammad Sadiq: I have added two gif image, one in xcode 9.1 with iOS 11.1 and another is Xcode 9.2 with ios 11.2, same code has been executed in both xcode in different machine. But in 11.2 it jerks but not in 11.1, it is quite strange for me too.Tenor
@AbhishekMitra, any luck with iOS11.2 ? I am facing the same issue. It was not jerking in iOS11.1 but now its showing jerk in 11.2. Let me know if u get any luck.Propraetor
@Propraetor I didn’t do any research after fixed that.. what r u getting ? Can u show gif and ur code snippet?Tenor
@AbhishekMitra, checkout this giphy.com/gifs/ios11-3ohjV9asyToN6M8tu8Propraetor
@Propraetor well i guess ur cell content size is bigger than your cell height size.. look into that thing once and make it sure..Tenor
@Propraetor now I'm facing such situation for ios 11.2, did u get something to stop it in ios 11.2 ?Tenor
@AbhishekMitra, I posted answer below. Please have a look. Good luck!Propraetor
T
4

**For ios 11.2.* **

tableView.rowHeight = UITableViewAutomaticDimension in viewDidLoad()

add estimatedHeightForRowAt

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {

        if indexPath.row == 0{

            return firstCellHeight()
        }
        else{

            return UITableViewAutomaticDimension
        }
}

firstCellHeight is my First Cell Height

func firstCellHeight() -> CGFloat{

    if UIDevice.Display.typeIsLike == UIDevice.DisplayType.ipad{

        return 400

    }else if UIDevice.Display.typeIsLike == UIDevice.DisplayType.iphone7plus{

        return 230

    }else if UIDevice.Display.typeIsLike == UIDevice.DisplayType.iphoneX{

        return 200

    }else{

        return 180
    }
}

and Don't use: reloadRows

    let indexPath = IndexPath(item: 1, section: 0)
    tableView.reloadRows(at: [indexPath], with: .none)

Instead use reloadData i.e tableView.reloadData()

And Finally Where your Action required, Use bellow code:

let indexPath0 = IndexPath(item: 0, section: 0)
        if !((tableView.indexPathsForVisibleRows?.contains(indexPath0))!) {
            print("Not Visible")

            self.tableView.setContentOffset(CGPoint(x:0, y:firstCellHeight() ), animated: false)
        }
Tenor answered 7/3, 2018 at 14:0 Comment(3)
use tableView.reloadData() after tableView.setContentOffsetTenor
Why use reloadData instead of reloadRows, if I need to reload several cells, not whole tableview?Huoh
Thank you helped me. Worked for me. Thank youRonen
P
11

What I understand is if you really want to use auto sizing cell(and all cell are of different sizes) then above solutions doesn't work for iOS 11.2, So what I tried is as below:

Declare variable to store the height of the cell

var cellHeightDictionary: NSMutableDictionary // To overcome the issue of iOS11.2

Initialize in viewDidLoad,

override func viewDidLoad() {
    super.viewDidLoad()
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 125
    cellHeightDictionary = NSMutableDictionary()
}

and use like below:

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    cellHeightDictionary.setObject(cell.frame.size.height, forKey: indexPath as NSCopying)
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    if cellHeightDictionary.object(forKey: indexPath) != nil {
        let height = cellHeightDictionary.object(forKey: indexPath) as! CGFloat
        return height
    }
    return UITableViewAutomaticDimension
}

This works for me, Hope this helps to you too

Propraetor answered 7/3, 2018 at 21:12 Comment(1)
Thanks Torap for investigating into it. I appreciate your answer by voting up. But I have solved that thing for ios 11.2 in my another answer, you can review it.Tenor
T
4

Finally I got the answer, I have to use an delegate method of UITableView i.e

    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {

            return UITableViewAutomaticDimension
    }

After putting this method by returning UITableViewAutomaticDimension it stop that jerking for iOS 11.2.

Tenor answered 7/12, 2017 at 12:29 Comment(1)
This works for me for 11.1 but not in 11.2. Issue is still present in iOS 11.2Propraetor
T
4

**For ios 11.2.* **

tableView.rowHeight = UITableViewAutomaticDimension in viewDidLoad()

add estimatedHeightForRowAt

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {

        if indexPath.row == 0{

            return firstCellHeight()
        }
        else{

            return UITableViewAutomaticDimension
        }
}

firstCellHeight is my First Cell Height

func firstCellHeight() -> CGFloat{

    if UIDevice.Display.typeIsLike == UIDevice.DisplayType.ipad{

        return 400

    }else if UIDevice.Display.typeIsLike == UIDevice.DisplayType.iphone7plus{

        return 230

    }else if UIDevice.Display.typeIsLike == UIDevice.DisplayType.iphoneX{

        return 200

    }else{

        return 180
    }
}

and Don't use: reloadRows

    let indexPath = IndexPath(item: 1, section: 0)
    tableView.reloadRows(at: [indexPath], with: .none)

Instead use reloadData i.e tableView.reloadData()

And Finally Where your Action required, Use bellow code:

let indexPath0 = IndexPath(item: 0, section: 0)
        if !((tableView.indexPathsForVisibleRows?.contains(indexPath0))!) {
            print("Not Visible")

            self.tableView.setContentOffset(CGPoint(x:0, y:firstCellHeight() ), animated: false)
        }
Tenor answered 7/3, 2018 at 14:0 Comment(3)
use tableView.reloadData() after tableView.setContentOffsetTenor
Why use reloadData instead of reloadRows, if I need to reload several cells, not whole tableview?Huoh
Thank you helped me. Worked for me. Thank youRonen
A
3

i had same issue. i was doing one thing wrong. Automatic Row Height & Automatic Estimate Height in Storyboard were selected and in code heightForRowAt method was also implemented. I un checked Automatic Row Height and only implemented heightForRowAt method. It resolved my issue.

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

enter image description here

Amphicoelous answered 14/4, 2019 at 11:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.