Summary
On iOS 27 the top scroll edge effect of a UITableView is sized around the UIRefreshControl as an edge element, but appears to key on the control's presence in the scroll view rather than its current height. After endRefreshing(), the control collapses to zero height but stays attached, and the effect region keeps reserving a refresh-control's worth of space. The first row stays blurred and dimmed even though it is scrolled fully clear of the navigation bar.
Environment
- iOS 27 (beta), iPhone
- Xcode 27.0.0 Beta 4
- UIKit, UITableView inside a UINavigationController
- Reproduces with the default edge effect style and with an explicit .soft
Steps to reproduce
- Push a UITableViewController with a UIRefreshControl onto a navigation stack.
- Ensure content extends under the navigation bar (default for UITableViewController).
- Pull to refresh and let the refresh end.
- Observe the first row after the refresh control has retracted.
Expected
Once the control retracts, the edge effect returns to its pre-pull height and the first row renders crisply.
Actual
The region stays roughly one refresh-control height too tall and the first row stays blurred. Row positions are unaffected — content offset and adjustedContentInset are correct. Only the extent of the effect is wrong. It corrects itself on the next push/pop.
Two probes that isolate it
These narrow the cause to the control's presence rather than a general staleness:
- Re-assigning
tableView.topEdgeEffect.styleafter endRefreshing(), including on a later runloop turn, does NOT correct the region. The style is not what is stale. - Detaching the control DOES correct it immediately: tableView.refreshControl = nil So the region is measured from the control being in the hierarchy, and is never re-measured when the control merely collapses.
Secondary issue
A UIRefreshControl that has been detached is inert if the same instance is re-assigned: tableView.refreshControl = nil tableView.refreshControl = sameInstance // never triggers again A freshly constructed UIRefreshControl must be assigned instead. This is not documented and looks like a second bug.
Minimal sample
Attached. A UITableViewController with a refresh control and a "Push" bar button that pushes and pops an empty view controller, so the incorrect region and the post-navigation correction can be compared in one run.
Related
FB20756572 reports the same "edge-effect extent is stale until the next navigation" behaviour for UIScrollEdgeElementContainerInteraction sizing, and notes a change in iOS 27 seed 1. That report received no reply.