Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
8
Help us understand the problem. What is going on with this article?
@u5_03

SwfitUIで通信中にIndicatorを表示できるようにする。

SwiftUIでLoadingの画面を表示したい!

先に現在できているコードを記載します。
また今回のコードのIndicator部分については、tsuzuki817さんの作りながら学ぶ! SwiftUIアニメーション インジケーター編を参考にさせていただきました。なのでIndicatorの実装に関する詳細は省略します。

struct LoadingIndicatorView: View {
    let isLoading: Bool
    @State private var isAnimating = false
    private let animation = Animation.linear(duration: 1).repeatForever(autoreverses: false)

    var body: some View {
        GeometryReader { geometry in
            ZStack {
                // ①Loading中に画面をタップできないようにするためのほぼ透明なLayer
                Color(.black)
                    .opacity(0.01)
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    .edgesIgnoringSafeArea(.all)
                    .disabled(self.isLoading)
                Circle()
                    .trim(from: 0, to: 0.6)
                    .stroke(AngularGradient(gradient: Gradient(colors: [.gray, .white]), center: .center),
                            style: StrokeStyle(
                                lineWidth: 8,
                                lineCap: .round,
                                dash: [0.1, 16],
                                dashPhase: 8))
                    .frame(width: 48, height: 48)
                    .rotationEffect(.degrees(self.isAnimating ? 360 : 0))
                    // ②アニメーションの実装
                    .onAppear() {
                        withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) {
                            self.isAnimating = true
                        }
                    }
                    .onDisappear() {
                        self.isAnimating = false
                    }
            }
             // ③Loading中だけLoading画面が表示されるようにする。
            .hidden(!self.isLoading)
        }
    }
}

使う時は、以下のように書きます。これでisLoadingの表示/非表示が切り替わります。

@State private var isLoading = false

var body: some View {
    ZStack {
        Text("Hello world!")
        LoadingIndicatorView(isLoading: self.isLoading)
    }
}

以下のGifの画面では、真ん中の青いボタンをタップすると、3秒間だけisLoadingtrueになるような実装をしてあるため、3秒間だけLoading画面が出るようになっています。またLoading画面中が表示されている間は、青いボタンはタップできないようになっています。
20200223_023345.GIF

実装詳細

①Loading中に画面をタップできないようにするためのほぼ透明なLayer

Color(.black)
    .opacity(0.01)
    .frame(width: geometry.size.width, height: geometry.size.height)
    .edgesIgnoringSafeArea(.all)
    .disabled(self.isLoading)

なぜ「ほぼ」透明になっているかというと、Color(.clear)にしてしまうと言うとdisabledを指定しても、画面へのジェスチャーが効いてしますからです。これに気づくまで結構時間がかかりました。綺麗な書き方も思いつかなかったので、とりあえず黒いLayerを作成し、それに.opacity(0.01)を設定することで、限りなく透明で、ユーザーのジェスチャーを無効化するLayerを作成することになんとか成功しました。これはSwiftUIのバグではないのか、、、、ちなみに色を.clear以外に指定すると、ちゃんとdisabledが効きます。

②アニメーションの実装
参考資料では以下のように書かれていましたが、これだとLoadingのアニメーションが実行されるたびに、インジェクターが時計回りと反時計回り、交互に回転するようになってしました。

.onAppear() {
    withAnimation(
        Animation
            .linear(duration: 1)) {
                self.isAnimation.toggle()
    }

そこでViewが表示されるonAppear()isAnimationtrueに、非表示になる onDisappear()falseにする実装に変更しました。
これで何度Loading画面を表示しても、ずーと時計回りにIndicatorが回転しています。

.onAppear() {
    withAnimation(self.animation) {
        self.isAnimating = true
    }
}
.onDisappear() {
    self.isAnimating = false
}

③Loading中だけLoading画面が表示されるようにする。
親ViewのisLoadingフラグに合わせて、Loading画面の表示/非表示が切り替わるような実装を行います。
該当箇所は以下の一行です。

.hidden(!self.isLoading)

hiddenは、カスタムのModifierです。詳細の実装については、こちらにまとめてあります。
問題はisLoadingの値をそのままhiddenに流すと、isLoadingtrueの時にLoading画面が非表示になってしまうので、!self.isLoadingとして、Booleanの値を入れ替えてhiddenに渡しています。

まとめ

SwiftUIは1つのファイルにまとめすぎると、かなり読みづらくなる印象があるので、カスタムのViewやModifier、extensionなどを作成して、コードを分割することで、可読性がかなり上がるなと思いました。
まだまだSwiftUIはUIKitと比較するとできることは限られていますが、これからはきっとSwiftUIが主流になっていくと思うので、SwiftUIのキャッチアップも進めていきたいですね。

参考資料

8
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
u5_03
SwiftでiOSアプリを作ってます〜

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
8
Help us understand the problem. What is going on with this article?