SwiftUIでSkeleton Screenを作る
最近YouTubeやSlackなどのアプリでよく見かけるSkeleton Screen(ローディング中のプレースホルダー表示)をSwiftUIで実装してみた。
Skeleton Screenとは?
Skeleton Screenとは、ローディング中に表示される骨組みのようなデザインのことで、スピナーと比べるとどんなコンテンツが表示されるのかがわかりやすいため、ローディング中の心理的負担が軽減されると言われている。また、シマーアニメーションと組み合わせて動きを付けることも多い。
SwiftUIでの実装方法
SwiftUIにはredacted(reason:)という便利なmodifierがあり、これを使えば簡単にViewをプレースホルダーで表示させることができる。
Text("テキスト")
// .placeholderでプレースホルダーが表示され、空配列の場合は通常表示
.redacted(reason: shouldBeRedacted ? .placeholder : [])
また、シマーアニメーションはSwiftUI-Shimmerという軽量なライブラリを使えば簡単に適用できる。ちなみに、ライブラリ内の実装では、ViewModifierを用意していて、LinearGradientのMaskを適用させて、Animation.linear(duration:)でグラデーションのハイライト箇所を移動させている。
Text("テキスト")
.redacted(reason: shouldBeRedacted ? .placeholder : [])
// これだけでシマーアニメーションを適用できる
.shimmering()
サンプルコード
import SwiftUI
import Shimmer
struct ListItem: Identifiable {
var id: Int
var iconName: String
var title: String
var text: String
}
struct ContentView: View {
@State private var isLoading = false
let items = Array(0..<20).map {
ListItem(id: $0,
iconName: "heart",
title: "\\($0+1)",
text: "List item\\($0+1)")
}
var body: some View {
List {
ForEach(items) { item in
HStack {
VStack(alignment: .leading, spacing: 8) {
Text(item.title)
.foregroundColor(isLoading ? .blue : .white)
.font(.system(size: 12))
.frame(minWidth: 20)
.padding(2)
.background(.blue)
.cornerRadius(4)
Text(item.text)
}
Spacer()
Image(systemName: item.iconName)
}
// isLoading中にプレースホルダーを表示する
.redacted(reason: isLoading ? .placeholder : [])
// シマーアニメーションを適用
.shimmering(active: isLoading)
}
}
.listStyle(.plain)
.task {
isLoading = true
defer { isLoading = false }
try? await Task.sleep(for: .seconds(5))
}
}
}
リポジトリ
参考
この記事が気に入ったらサポートをしてみませんか?