2
\$\begingroup\$

I have a tableView, which auto locates back at indexPath after user has dragged it.

In other words, bouncing the tableView back into its bounds, after user dragged it out.

Here is the code:

// ...

var tracking = false
var currentPath = 0

@objc func updateRecorder(_ timer: Timer){
     currentPath = somethingCalculated
}

// ...

extension ViewController: UITableViewDelegate{


    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
            // when the scene is in a special state
            tracking = true
        }
    }

    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        // when the scene is in the same special state
        if tracking == true{
            tracking = false
            scrollToRow(at: IndexPath(row: currentPath, section: 0), at: UITableView.ScrollPosition.middle, animated: true)
        }
    }
}

In fact, it is a music tracking app. People sing a song, the lyric tableView tracks the voice, and it auto scrolls to current line.

When tracking, and people scrolls by hand, the lyric tableView should bounces back to it ought to be.

The code above works.

Any other ideas?

\$\endgroup\$
4
  • \$\begingroup\$ The purpose is not yet entirely clear to me. After a user scrolls the tableview, it always scrolls back? \$\endgroup\$
    – Martin R
    Commented Nov 1, 2019 at 14:17
  • \$\begingroup\$ YES, there is a timer and a AVAudioEngine. the AVAudioEngine has a tap to get the current PCM buffer, the timer regularly calls analyzing the PCM buffer, to get the current line of the lyric, indexPath. So after the user scrolls the lyric tableView, it always scrolls back to the line of the lyric calculated . \$\endgroup\$
    – dengApro
    Commented Nov 1, 2019 at 18:57
  • \$\begingroup\$ But you don't want to disable user scrolling? \$\endgroup\$
    – Martin R
    Commented Nov 1, 2019 at 19:07
  • \$\begingroup\$ Yes, the user can scroll to see the lyrics , if they want \$\endgroup\$
    – dengApro
    Commented Nov 2, 2019 at 5:20

1 Answer 1

2
\$\begingroup\$

A couple of observations:

  1. You are handling scrollViewDidEndDecelerating. But what if there was no deceleration? E.g. you’d generally want to call some common routine, e.g. didFinishUserScroll, either way:

    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
        if !decelerate {
            didFinishUserScroll()
        }
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        didFinishUserScroll()
    }
    
  2. It looks like you are scrolling as soon as deceleration finishes. I would suggest that you only want to scroll at the end of the user gesture (whether decelerating or not) only if there is an update to the position in the lyrics in the intervening period of time.

    E.g. you’re bopping along in a song, the drummer goes off into some lengthy, lyric-free solo, so the bored user starts scrolling through the lyrics themselves. When they let go, if the drum solo is still in progress, I’d suggest that you might not want to scroll back until the singing resumes. I wouldn’t necessarily scroll back immediately.

    Now maybe you’ve got the sort of logic in the code you didn’t share with us, and if so, don’t worry about it. But, frankly, the fact that tracking is so ambiguous is code smell. (I.e., is it a boolean whether a touch gesture is in progress? is it indicating that we’re following along with lyrics at all? is it that there are updates to progress in the song that requires update of the position?) The fact that the intent of tracking is so ambiguous suggests you might consider a better name for it.

  3. It looks like currentPath is an Int, a row number. So I wouldn’t call it currentPath, but rather currentRow.

  4. When you have a boolean, you generally just check the value, not compare it to another boolean. So, for example, instead of:

    if tracking == true {
        tracking = false
        scrollToRow(at: IndexPath(row: currentPath, section: 0), at: UITableView.ScrollPosition.middle, animated: true)
    }
    

    You would do:

    if tracking {
        tracking = false
        scrollToRow(at: IndexPath(row: currentPath, section: 0), at: .middle, animated: true)
    }
    

    I also removed the redundant UITableView.ScrollPosition reference.

  5. This is beyond the scope of this question, but the fact that you’re calling scrollToRow(at:at:animated:) without referencing the table view worries me, making me wonder whether you have all of this business logic buried inside your table view. We generally strive to isolate our UI from business logic of the app.

\$\endgroup\$
1
  • \$\begingroup\$ Your insight is impressive. ` I’d suggest that you might not want to scroll back until the singing resumes. I wouldn’t necessarily scroll back immediately.` , our company product logic has not planned so sweetly yet. The rest of insights are also nice. \$\endgroup\$
    – dengApro
    Commented Nov 2, 2019 at 18:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.