Swift4.1环境下如何检测tableView.scrollToRow结束及解决冲突
Hey there, let's break down your problem into two clear parts: the conflict between tableView.scrollToRow(at:) and reloadData(), and how to detect when the scroll-to-row animation finishes. I’ve run into similar quirks before, so here’s what works for me:
1. Fixing the Conflict Between ScrollToRow and ReloadData
Why the Conflict Happens
When you call reloadData() while scrollToRow(at:) is still animating, the tableView immediately recalculates cell layouts, heights, and positions. This interrupts the scroll animation’s planned path—either the target cell’s position shifts mid-scroll, or the animation gets cut off entirely, leading to glitches or unexpected behavior.
The Solution: Delay Reload Until Scroll Finishes
Instead of reloading immediately when you get data2, check if the tableView is still scrolling to your target row. If it is, cache data2 and wait for the scroll to finish before updating the table. This ties directly into the second part of your question: detecting when the scroll ends.
2. Detecting When scrollToRow(at:) Finishes
Since UITableView inherits from UIScrollView, we can use scroll view delegate methods to track the end of the scroll animation. Here’s how to handle both animated and non-animated scenarios:
For Animated Scrolls
Use the scrollViewDidEndScrollingAnimation(_:) delegate method—this is specifically triggered when a programmatic scroll (like scrollToRow(at:) with animated: true) finishes.
For Non-Animated Scrolls
If you’re using animated: false, the scroll happens instantly, so you can treat the line right after scrollToRow(at:) as the end of the scroll.
Step-by-Step Implementation
First, add state variables to your view controller to track scroll status and cache pending data:
var isScrollingToTarget = false var pendingData2: [YourDataType]? // Replace with your actual data type
Update your data handling logic to respect the scroll state:
// When you receive data1 and need to scroll to a target row func handleData1(_ data1: [YourDataType]) { yourDataSource = data1 tableView.reloadData() // Define your target index path (adjust this to your needs) let targetIndexPath = IndexPath(row: yourTargetRow, section: 0) isScrollingToTarget = true tableView.scrollToRow(at: targetIndexPath, at: .top, animated: true) } // When you receive data2 func handleData2(_ data2: [YourDataType]) { if isScrollingToTarget { // Scroll is in progress—cache the data for later pendingData2 = data2 } else { // No scroll active—update the table immediately yourDataSource.append(contentsOf: data2) // Or your preferred update logic tableView.reloadData() } }
Implement the scroll view delegate method to handle the end of the animation:
extension YourViewController: UIScrollViewDelegate { func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) { isScrollingToTarget = false // Check if there's pending data to load if let data2 = pendingData2 { yourDataSource.append(contentsOf: data2) tableView.reloadData() pendingData2 = nil // Optional: Re-scroll to the target if data2 changes its position // let newTargetIndexPath = IndexPath(row: updatedTargetRow, section: 0) // tableView.scrollToRow(at: newTargetIndexPath, at: .top, animated: true) } } }
Edge Case: Non-Animated Scroll
If you’re using animated: false, update your scroll logic to handle pending data right away:
func scrollToTargetWithoutAnimation() { let targetIndexPath = IndexPath(row: yourTargetRow, section: 0) tableView.scrollToRow(at: targetIndexPath, at: .top, animated: false) isScrollingToTarget = false // Process any cached data immediately if let data2 = pendingData2 { yourDataSource.append(contentsOf: data2) tableView.reloadData() pendingData2 = nil } }
Extra Tips
- Always verify your target index path is still valid after updating
data2! Ifdata2adds/removes rows before your target, recalculate the correct index path to avoid crashes. - If using auto-sizing cells, double-check your cell constraints—bad constraints can make scroll-to-row behavior even more unpredictable when combined with
reloadData().
内容的提问来源于stack exchange,提问作者iKK

