Pull to Refresh(refreshable)
リストを下に引っ張って更新する「Pull to Refresh」は、多くのアプリで採用されている UI パターンです。SwiftUI では refreshable モディファイアを使って簡単に実装できます。
refreshable の基本
refreshable モディファイアを List に適用するだけで、Pull to Refresh 機能が有効になります。
struct ContentView: View {
@State private var items = ["項目1", "項目2", "項目3"]
var body: some View {
List(items, id: \.self) { item in
Text(item)
}
.refreshable {
// 更新処理
await loadData()
}
}
func loadData() async {
// API からデータを取得するなど
try? await Task.sleep(nanoseconds: 1_000_000_000) // 1秒待機
items.append("新しい項目")
}
}refreshable のクロージャは async コンテキストで実行されるため、await を使った非同期処理が可能です。更新インジケーターは処理が完了するまで自動的に表示されます。
API からデータを取得する例
実践的な例として、API からデータを取得してリストを更新するパターンを見てみましょう。
struct Article: Identifiable, Codable {
let id: Int
let title: String
}
struct ArticleListView: View {
@State private var articles: [Article] = []
@State private var isLoading = true
var body: some View {
NavigationStack {
List(articles) { article in
Text(article.title)
}
.refreshable {
await fetchArticles()
}
.overlay {
if isLoading {
ProgressView()
}
}
.navigationTitle("記事一覧")
.task {
await fetchArticles()
}
}
}
func fetchArticles() async {
defer { isLoading = false }
guard let url = URL(string: "https://api.example.com/articles") else { return }
do {
let (data, _) = try await URLSession.shared.data(from: url)
articles = try JSONDecoder().decode([Article].self, from: data)
} catch {
print("Error: \(error)")
}
}
}更新処理のポイント
自動的なインジケーター管理
refreshable のクロージャが完了するまでインジケーターが表示され、完了後に自動で消える。
async/await 対応
非同期処理を自然に記述できる。Task.sleep で擬似的な遅延を入れてテストすることも可能。
エラーハンドリング
do-catch でエラーをキャッチし、適切に処理する。ユーザーへのフィードバックも忘れずに。
ScrollView での refreshable
List だけでなく、ScrollView でも refreshable を使うことができます。
struct ContentView: View {
@State private var counter = 0
var body: some View {
ScrollView {
VStack(spacing: 20) {
ForEach(0..<10) { i in
Text("カード \(i + counter)")
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue.opacity(0.1))
.cornerRadius(10)
}
}
.padding()
}
.refreshable {
try? await Task.sleep(nanoseconds: 500_000_000)
counter += 10
}
}
}RefreshAction 環境値
refreshable で設定した更新処理は、子ビューから RefreshAction 環境値を通じて呼び出すこともできます。
struct ParentView: View {
@State private var data = ["A", "B", "C"]
var body: some View {
List(data, id: \.self) { item in
ChildRow(item: item)
}
.refreshable {
try? await Task.sleep(nanoseconds: 1_000_000_000)
data.shuffle()
}
}
}
struct ChildRow: View {
let item: String
@Environment(\.refresh) private var refresh
var body: some View {
HStack {
Text(item)
Spacer()
Button("更新") {
Task {
await refresh?()
}
}
}
}
}refreshable はシンプルな API ながら、モダンなアプリに欠かせない Pull to Refresh 機能を手軽に実装できる強力なモディファイアです。











