如何通过代码触发SwiftUI原生.refreshable加载动画?
问题
我给SwiftUI的List添加了.refreshable修饰符,手动下拉刷新时功能正常。但我需要在特定条件变化时(比如通过按钮点击触发),用代码触发同样的刷新动画。目前调用refresh()方法只能执行刷新逻辑,看不到和手动下拉一致的原生加载动画,想问下能不能通过代码触发原生的.refreshable动画,还是必须自己做个模仿原生样式的自定义刷新指示器?
代码示例:
struct ContentView: View { @State private var refreshTimes = 0 var body: some View { List{ Text("refresh times: \(refreshTimes)") Button("click me to refresh") { refresh() } } .refreshable { refresh() } } func refresh() { refreshTimes += 1 print("refresh at :\(Date())") } }
解决方案
目前SwiftUI原生的.refreshable并没有提供直接触发动画的公开API,不过可以通过两种方式实现需求:
方法一:利用ScrollViewProxy模拟下拉刷新(推荐)
通过ScrollViewReader获取ScrollViewProxy,手动将列表滚动到超出顶部的位置,触发原生刷新动画,之后再恢复原位置。这种方式能完全复用原生的刷新指示器和动画逻辑:
struct ContentView: View { @State private var refreshTimes = 0 @State private var isProgrammaticRefresh = false var body: some View { ScrollViewReader { proxy in List{ Text("refresh times: \(refreshTimes)") Button("click me to refresh") { isProgrammaticRefresh = true // 滚动到顶部外的位置触发刷新 proxy.scrollTo(-1, anchor: .top) DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { isProgrammaticRefresh = false proxy.scrollTo(0, anchor: .top) // 恢复原位置 } } } .refreshable { refresh() } .onAppear { // 给列表添加初始锚点 proxy.scrollTo(0, anchor: .top) } } } func refresh() { refreshTimes += 1 print("refresh at :\(Date())") } }
注:这里的-1和0是自定义锚点ID,你也可以给列表第一个元素设置明确ID,滚动到该ID上方来触发刷新。
方法二:自定义刷新指示器
如果觉得滚动模拟不够优雅,可以自己实现一个和原生样式一致的刷新指示器,通过状态控制显示时机,灵活性更高:
struct ContentView: View { @State private var refreshTimes = 0 @State private var isRefreshing = false var body: some View { List{ if isRefreshing { ProgressView() .frame(maxWidth: .infinity) } Text("refresh times: \(refreshTimes)") Button("click me to refresh") { guard !isRefreshing else { return } isRefreshing = true refresh() } } .refreshable { isRefreshing = true refresh() } } func refresh() { // 模拟异步刷新过程 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { refreshTimes += 1 isRefreshing = false print("refresh at :\(Date())") } } }
这个自定义的ProgressView和原生刷新指示器样式基本一致,通过isRefreshing状态控制显示,手动下拉和按钮触发都能同步展示动画。
内容的提问来源于stack exchange,提问作者ximmyxiao
相关产品推荐
相关产品推荐

