LoginSignup
41
29

More than 3 years have passed since last update.

SwiftUI: `.redacted` を使ってインターネットからデータ取得するときに、簡単にプレースホルダーのオーバーレイを追加できます。

Last updated at Posted at 2020-11-18

APIから情報をフェッチしている間、空白の画面を表示することは避けたいものです。ローディングインジケータを表示するべきでしょう。あるいは、ビューにSwiftUIのプレースホルダ―オーバーレイを設置することもできます。

image

この記事では .redacted を使って簡単にプレースホルダ―オーバーレイを追加する方法、ビューのプレースホルダーオーバーレイ表示ステータスを監視する方法、プレースホルダーオーバーレイにアニメーションを追加する方法について述べます。

.redacted.unredacted() ビューモディファイア

.redacted モディファイアは、データのダウンロードを行っている最中には非表示にしたいビュー要素に追加することができます。

.redacted(reason: (weatherInformation == nil) ? .placeholder : [])

reason.placeholder と等しい場合、オーバーレイがビューに追加されます。また、reason 変数が空配列と等しい場合は表示されるプレースホルダーオーバーレイはありません。

また、テキストビュー要素用に何らかのデフォルト値を指定する必要もあります。それにより、生成するプレースホルダーのサイズをSwiftUIが把握します。例えば

Text(weatherInformation?.weatherDescription ?? "気象情報をダウンロードしています...")

常にスクリーンに表示しておきたいエレメントに対しては、.unredacted() ビューモディファイヤーを追加してください。

プレイスホルダーを表示するかどうかをチェックするための拡張を追加する

コードに拡張を追加することもできます:

extension View {
    @ViewBuilder
    func redacted(showPlaceholder: Bool) -> some View {
        if showPlaceholder {
            self
                .redacted(reason: .placeholder)
        } else {
            self
                .unredacted()
        }
    }
}

よって showPlaceholder 変数によって容易にプレイスホルダーを表示するか隠すかを決定できます

.redacted(showPlaceholder: (weatherInformation == nil))

SwiftUIビューへのビュー修飾子の適用

まず、基本的な気象情報を表示するSwiftUIビューがあります。

struct WeatherView: View {

    @Binding var weatherInformation: Weather?
    @Environment(\.redactionReasons) var redactions

    var body: some View {

        HStack {
             Image("sunnyImage")
                .resizable()
                .scaledToFit()
                .frame(width: 100, height: 100)
                .unredacted()
            VStack(alignment: .leading) {
                Text(weatherInformation?.status ?? "ダウンロードしています...")
                    .font(.largeTitle)
                    .padding(.vertical, 3)
                Text(weatherInformation?.weatherDescription ?? "気象情報をダウンロードしています...")
                    .padding(.vertical, 3)
                Label(weatherInformation?.degrees ?? "...", systemImage: "thermometer.sun")
                    .font(.title2)
                    .padding(.vertical, 3)
            }
        }

    }

}

1> このビューのコードでは、SwiftUIが自動的にオーバーレイを生成することができるように、テキストとラベルのデフォルト値を指定する必要があります。
2> 上記の例の Image オブジェクトには、修飾子 .unredacted() があります。これは、ユーザーに常に表示されることを意味します。

コンテンツ閲覧に作成されたばかりの WeatherView でそれを用いることができます。

Section {
    WeatherView(weatherInformation: $weatherInformation)
        .redacted(reason: (weatherInformation == nil) ? .placeholder : [])
        //.redacted(showPlaceholder: (weatherInformation == nil))
}

WeatherView 内の画像以外の閲覧対象が表示されるのは weatherInformation == nil 条件が当てはまらない場合のみです。

そしてこの例では、weatherInformation を設定することができます。

.onAppear(perform: {
    DispatchQueue.main.asyncAfter(deadline: .now() + 3.5) {
        self.weatherInformation = Weather(status: "晴れ", weatherDescription: "今日の東京の天気は晴れです。", degrees: "23度")
    }
})

プレースホルダーオーバーレイのモニター

@Environment 変数 \.redactionReasons を使って WeatherView に加えられたプレースホルダーオーバーレイの有無をモニターすることができます。

@Environment(\.redactionReasons) var redactions
if self.redactions.isEmpty {
    Button(action: {}, label: {
        Text("天気予報のビュー表示")
    })
}

​データのダウンロード中にアニメーションを追加する

データのダウンロード中にアニメーションを追加することもできます。​例えば、プレースホルダーのオーバーレイをぼかすアニメーションを追加したり、不透明度を変更したりすることができます。

​ここでは、ビューにアニメーションを追加するビューのモディファイア struct を作成する必要があります。​これはビューの不透明度を1.0から0.3に変更して繰り返す例の1つです。

struct EaseInOutAnimation: ViewModifier {

    @State private var contentOpacity = 1.0

    func body(content: Content) -> some View {
        content
            .opacity(contentOpacity)
            .animation(Animation
                        .easeInOut(duration: 2)
                        .repeatForever(autoreverses: true))
            .onAppear { contentOpacity = 0.3 }
    }

}

この EaseInOutAnimation ビュー修飾子をビュー拡張機能の編集済み修飾子に適用することができます:

extension View {
    @ViewBuilder
    func redacted(showPlaceholder: Bool) -> some View {
        if showPlaceholder {
            self
                .redacted(reason: .placeholder)
                .modifier(EaseInOutAnimation())
        } else {
            self
                .unredacted()
        }
    }
}

これで、もし showPlaceholder が真であれば、プレースホルダーが表示され、 EaseInOutAnimation アニメーションもビューに適用されます。


WeatherView と ContentView コード例を見る


:relaxed: Twitter @MszPro

:sunny: 私の公開されているQiita記事のリストをカテゴリー別にご覧いただけます。

41
29
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
29