How to perform updates on UITableView while scrolling using CADisplayLink and UITableViewAutomaticDimension without jumping?
Asked Answered
S

1

11

Link to the subclass of UITableView

I want to find out why UITableView jumps while scrolling.

How to perform some changes on UITableView along with setting its contentOffset?

This is how I set up my scrollDisplayLink:

scrollDisplayLink = CADisplayLink(target: self, selector: Selector("scrollTable"))
scrollDisplayLink?.addToRunLoop(NSRunLoop.mainRunLoop(), forMode: NSRunLoopCommonModes)
cellForCurrentIndexPath?.hidden = true

and then within scrollTable I do following things:

func scrollTable() {
    var newOffset = CGPointMake(currentContentOffset.x, currentContentOffset.y + scrollRate * 10)
    
    if currentContentSize.height < frame.size.height {
        newOffset = currentContentOffset
    } else if newOffset.y > currentContentSize.height - frame.size.height {
        newOffset.y = currentContentSize.height - frame.size.height
    } else if newOffset.y < 0 {
        newOffset = CGPointZero
    }

    contentOffset = newOffset


    if coveredIndexPath != nil && coveredIndexPath! != currentIndexPath! {
    
        let verticalPositionInCoveredCell = longPressGestureRecognizer.locationInView(cellForRowAtIndexPath(coveredIndexPath!)).y
        
        if direction == .Down && heightForCoveredCell - verticalPositionInCoveredCell <= heightForCurrentCell / 2 {
                print("moved down")
            
                beginUpdates() //1
                moveRowAtIndexPath(currentIndexPath!, toIndexPath: coveredIndexPath!)  //2
                currentIndexPath = coveredIndexPath //3
                endUpdates() //4

        }
    }
}

Scrolling is fine unless lines 1-4 are commented or I disable UITableViewAutomaticDimension. When they are not commented the table jumps when currentContentOffset is different then 0 while scrolling. Why it happens like that? Is it problem with threads or something else?

Note

UITableView works with UITableViewAutomaticDimension:

func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
Swatter answered 19/9, 2015 at 23:9 Comment(0)
D
0

Let's start with the obvious:

UITableView is a subclass of UIScrollView and we can use some properties of that.

Almost each year there is an excellent WWDC talk about how to customize UIScrollviews.

They suggest to do things like you do inside

// is called every frame of scrolling and zooming
override func layoutSubviews() {
    ...
    super.layoutSubviews()
    ...
}

which is called each frame while the user is scrolling.

I've used this place heavily to mess around with currentContentOffset and size and coordinate systems while scrolling (I subclassed UIScrollView and not UITableView).

Advantages:

  • you get your callbacks each frame for free, no need to use CADisplayLink
  • you are changing things tike contentOffset exactly when the UIScrollView expects it to be changed.

Hope this helps

P.S.

according to my experiments, the view that is scrolled inside a UIScrollView can be not higher than around 8000 pixels.

So Apples UITableView has to implement a strategy that is called infinite scrolling and is described in one of the WWDC videos about UIScrollViews:

in short:

a fraction of the table is drawn once and then scrolled without redrawing the table content. When the user scrolls too far, a different part of the scrolled table is drawn and at the same time contentOffset is changed by the UITableView implementation.

This is probably done when you call super.layoutSubviews() in your implementation of layoutSubviews().

Dynameter answered 21/10, 2015 at 14:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.