1. ホーム
  2. swiftui

[解決済み] SwiftUIでのアクティビティ表示

2022-04-22 16:09:07

質問

SwiftUIでフルスクリーンのアクティビティインジケータを追加しようとしています。

を使用することができます。 .overlay(overlay: ) 関数を View プロトコルです。

これで、任意のビューオーバーレイを作ることができるのですが、iOSのデフォルトスタイルである UIActivityIndicatorView に相当します。 SwiftUI .

でデフォルトスタイルのスピナーを作るにはどうしたらよいでしょうか? SwiftUI ?

NOTE UIKitフレームワークでアクティビティインジケータを追加することではありません。

解決するには?

現在 Xcode 12ベータ版 ( iOS 14 という新しいビューが追加されました。 ProgressView 開発者向け そして、確定的な進捗と不確定な進捗の両方を表示することができる。

スタイルのデフォルトは CircularProgressViewStyle これはまさに私たちが求めているものです。

var body: some View {
    VStack {
        ProgressView()
           // and if you want to be explicit / future-proof...
           // .progressViewStyle(CircularProgressViewStyle())
    }
}


Xcode 11.x

かなりの数のビューが、まだ SwiftUI しかし、それらをシステムに移植するのは簡単です。 をラップする必要があります。 UIActivityIndicator とし、それを UIViewRepresentable .

(これについては、WWDC 2019の素晴らしい講演で見ることができます -。 SwiftUIの統合 )

struct ActivityIndicator: UIViewRepresentable {

    @Binding var isAnimating: Bool
    let style: UIActivityIndicatorView.Style

    func makeUIView(context: UIViewRepresentableContext<ActivityIndicator>) -> UIActivityIndicatorView {
        return UIActivityIndicatorView(style: style)
    }

    func updateUIView(_ uiView: UIActivityIndicatorView, context: UIViewRepresentableContext<ActivityIndicator>) {
        isAnimating ? uiView.startAnimating() : uiView.stopAnimating()
    }
}

そして、以下のように使用することができます。ここでは、ローディングオーバーレイの例を示します。

注:私は ZStack よりも、むしろ overlay(:_) そのため、私の実装では何が起こっているのか、正確に把握することができます。

struct LoadingView<Content>: View where Content: View {

    @Binding var isShowing: Bool
    var content: () -> Content

    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .center) {

                self.content()
                    .disabled(self.isShowing)
                    .blur(radius: self.isShowing ? 3 : 0)

                VStack {
                    Text("Loading...")
                    ActivityIndicator(isAnimating: .constant(true), style: .large)
                }
                .frame(width: geometry.size.width / 2,
                       height: geometry.size.height / 5)
                .background(Color.secondary.colorInvert())
                .foregroundColor(Color.primary)
                .cornerRadius(20)
                .opacity(self.isShowing ? 1 : 0)

            }
        }
    }

}

テストするには、このサンプルコードを使用します。

struct ContentView: View {

    var body: some View {
        LoadingView(isShowing: .constant(true)) {
            NavigationView {
                List(["1", "2", "3", "4", "5"], id: \.self) { row in
                    Text(row)
                }.navigationBarTitle(Text("A List"), displayMode: .large)
            }
        }
    }

}

結果