SwiftUI下拉刷新怎么实现?手把手教你加进列表里

刷微博、看新闻、逛购物App,手指一拉就刷新新内容——这已经成了大家的肌肉记忆。在 SwiftUI 里想给 List 或 ScrollView 加个下拉刷新,其实不难,但得用对方法。iOS 15 开始,SwiftUI 原生支持 .refreshable 修饰符,不用再折腾第三方库或者硬套 UIKit 的 UIRefreshControl

最简写法:一行搞定

假设你有个展示文章标题的列表:

struct ArticleView: View {
    @State private var articles = ["iOS 18 新特性","SwiftUI 动画技巧","Xcode 16 使用避坑"]
    
    var body: some View {
        List(articles, id: \.self) { title in
            Text(title)
        }
        .refreshable {
            // 模拟网络请求
            await Task.sleep(nanoseconds: 1_500_000_000)
            articles.insert("刚刷新的第" + String(articles.count + 1), at: 0)
        }
    }
}

下拉时会自动出现那个熟悉的旋转圆圈,松手后执行闭包里的逻辑,刷新完成后动画收起。注意:.refreshable 要求闭包是 async 的,所以里面可以直接用 await 调用异步函数。

配合真实网络请求

实际项目中,你大概率要调接口。比如从一个假 API 拉最新 3 条新闻:

func fetchLatestNews() async -> [String] {
    guard let url = URL(string: "https://api.example.com/news?limit=3") else { return [] }
    do {
        let (data, _) = try await URLSession.shared.data(from: url)
        return try JSONDecoder().decode([String].self, from: data)
    } catch {
        print("加载失败:\($0)")
        return []
    }
}

然后在 View 里这样用:

.refreshable {
    let newItems = await fetchLatestNews()
    articles = newItems + articles
}

旧系统兼容(iOS 14 及以下)

如果你还得支持 iOS 14,.refreshable 不可用,就得桥接 UIKit。新建一个 RefreshableScrollView 封装 UIRefreshControl,再用 UIViewRepresentable 包一层。不过现在绝大多数用户都升到 iOS 15+ 了,除非你做企业内网 App 或明确要求兼容老系统,否则真没必要绕这么大弯。

小提醒几个坑

• 列表为空时下拉也会触发刷新,这是正常行为,别误以为没生效;
• 如果用的是自定义 ScrollView + LazyVStack,记得加上 .refreshable 在 ScrollView 外层,不是 Stack 里面;
• 刷新过程中用户又猛拉一次?不会重复触发,SwiftUI 会自动节流。

顺手试一试,把上面那段代码粘进 Xcode 的预览里,下拉看看效果——比想象中快多了。