32
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WidgetのオススメPreview一覧(iOS)

Last updated at Posted at 2020-12-10

はじめに

本記事は iOS Advent Calendar 2020 の10日目の記事です。
昨日は @417_72ki さんで SwiftのKeyPathと戯れる でした。

iOS 14で追加されたWidgetのオススメPreviewを紹介します。

環境

  • OS:macOS Big Sur 11.0.1
  • Xcode:12.2 (12B45b)
  • Swift:5.3.1

対象コード

対象WidgetのEntryViewとEntryのコードを載せます。
長いので折りたたみにします。
本筋ではないので読み飛ばしても構いません。

EntryViewのコード
MonsterEntryView.swift
import WidgetKit
import SwiftUI

struct MonsterEntryView: View {
    var entry: MonsterWidget.Provider.Entry
    @Environment(\.widgetFamily) private var family

    var body: some View {
        switch family {
        case .systemSmall:
            ZStack {
                Color(.systemBackground)
                VStack {
                    icon
                    Spacer(minLength: 8.0)
                    name
                }
                .padding()
            }
        case .systemMedium:
            ZStack {
                Color(.systemBackground)
                HStack {
                    VStack {
                        icon
                        Spacer(minLength: 8.0)
                        name
                    }
                    Spacer(minLength: 16.0)
                    description
                }
                .padding()
            }
        case .systemLarge:
            EmptyView()
        @unknown default:
            EmptyView()
        }
    }

    private var icon: some View {
        Image(uiImage: entry.icon)
            .resizable()
            .aspectRatio(contentMode: .fit)
    }

    private var name: some View {
        Text(entry.name)
            .font(.headline)
    }

    private var description: some View {
        Text(entry.description)
            .font(.body)
    }
}
Entryのコード
MonsterWidget.swift
struct MonsterWidget: Widget { ... }

extension MonsterWidget {
    struct Entry: TimelineEntry {
        let date: Date
        let name: String
        let description: String
        let icon: UIImage

        static func createDefault() -> Entry {
            .init(
                date: Date(),
                name: "uhooi",
                description: "ゆかいな みどりの せいぶつ。\nわるそうに みえるが むがい。",
                icon: UIImage(named: "Uhooi")!
            )
        }
    }
}

Previewに不要なWidgetとProviderのコードは省略します。
参考リンクにあるウホーイ図鑑のコードをご参照ください。

WidgetのオススメPreview一覧

WidgetのオススメPreview一覧を紹介します。

プレースホルダー

プレースホルダーの表示をプレビューします。
EntryViewに .redacted(reason: .placeholder) を付けると、プレースホルダーで表示します。

コード

MonsterEntryView.swift
struct MonsterEntryView_Previews: PreviewProvider {
    static var previews: some View {
        // プレースホルダー
        MonsterEntryView(entry: .createDefault())
            .redacted(reason: .placeholder) // !!!
            .previewContext(WidgetPreviewContext(family: .systemSmall)) // Mediumの場合は `.systemMedium` を指定する
        }
    }
}

プレビュー

Small Medium
スクリーンショット 2020-12-10 22.05.32.png スクリーンショット 2020-12-10 22.06.20.png

通常

通常の表示をプレビューします。
プレースホルダーのプレビューから .redacted(reason: .placeholder) を取り除くのみです。

コード

MonsterEntryView.swift
struct MonsterEntryView_Previews: PreviewProvider {
    static var previews: some View {
        // 通常
        MonsterEntryView(entry: .createDefault())
            .previewContext(WidgetPreviewContext(family: .systemSmall))
        }
    }
}

プレビュー

Small Medium
スクリーンショット 2020-12-10 22.05.40.png スクリーンショット 2020-12-10 22.06.30.png

ダークモード

ダークモードの表示をプレビューします。
通常のプレビューに .environment(\.colorScheme, .dark) を付けるのみです。

コード

MonsterEntryView.swift
struct MonsterEntryView_Previews: PreviewProvider {
    static var previews: some View {
        // ダークモード
        MonsterEntryView(entry: .createDefault())
            .environment(\.colorScheme, .dark) // !!!
            .previewContext(WidgetPreviewContext(family: .systemSmall))
        }
    }
}

プレビュー

Small Medium
スクリーンショット 2020-12-10 22.05.50.png スクリーンショット 2020-12-10 22.06.39.png

短い文字列

短い文字列の表示をプレビューします。
Previewを使うと境界値の表示もかんたんに確認できます。

コード

MonsterEntryView.swift
struct MonsterEntryView_Previews: PreviewProvider {
    typealias Entry = MonsterWidget.Entry

    static var previews: some View {
        // 短い文字列
        MonsterEntryView(entry: createShortEntry())
            .previewContext(WidgetPreviewContext(family: .systemSmall))
        }
    }

    private static func createShortEntry() -> Entry {
        .init(
            date: Date(),
            name: "1",
            description: "1",
            icon: UIImage(named: "Uhooi")!
        )
    }
}

プレビュー

Small Medium
スクリーンショット 2020-12-10 22.06.02.png スクリーンショット 2020-12-10 22.06.51.png

Mediumで 1 が右寄せなのが気になります。
おそらく HStackSpacer() を使えば左寄せにできますが、短い文字列が入ることを想定していないので、このままとしています。

長い文字列

長い文字列の表示をプレビューします。
短い文字列と同様の方法です。

コード

MonsterEntryView.swift
struct MonsterEntryView_Previews: PreviewProvider {
    typealias Entry = MonsterWidget.Entry

    static var previews: some View {
        // 長い文字列
        MonsterEntryView(entry: createLongEntry())
            .previewContext(WidgetPreviewContext(family: .systemSmall))
        }
    }

    private static func createLongEntry() -> Entry {
        .init(
            date: Date(),
            name: "123456789012345678901234567890",
            description: "12345678901234567890\n12345678901234567890\n12345678901234567890",
            icon: UIImage(named: "Uhooi")!
        )
    }
}

プレビュー

Small Medium
スクリーンショット 2020-12-10 22.06.09.png スクリーンショット 2020-12-10 22.07.02.png

Small・Mediumの両方で画像が小さくなるのが気になりますが、モンスター名が長くなることを想定していないので、このままとしています。
「…」になるのも気になりますが、同様の理由でこのままとしています。

全体図

上記のコードをいい感じにまとめました。

MonsterEntryView.swift
struct MonsterEntryView_Previews: PreviewProvider {
    typealias Entry = MonsterWidget.Entry

    static var previews: some View {
        ForEach(families.indices) { index in
            previewEntryViewGroup
                .previewContext(WidgetPreviewContext(family: families[index]))
        }
    }

    private static let families: [WidgetFamily] = [.systemSmall, .systemMedium]

    private static var previewEntryViewGroup: some View {
        Group {
            MonsterEntryView(entry: .createDefault())
                .redacted(reason: .placeholder)
            MonsterEntryView(entry: .createDefault())
            MonsterEntryView(entry: .createDefault())
                .environment(\.colorScheme, .dark)
            MonsterEntryView(entry: createShortEntry())
            MonsterEntryView(entry: createLongEntry())
        }
    }

    private static func createShortEntry() -> Entry {
        .init(
            date: Date(),
            name: "1",
            description: "1",
            icon: UIImage(named: "Uhooi")!
        )
    }

    private static func createLongEntry() -> Entry {
        .init(
            date: Date(),
            name: "123456789012345678901234567890",
            description: "12345678901234567890\n12345678901234567890\n12345678901234567890",
            icon: UIImage(named: "Uhooi")!
        )
    }
}

おわりに

これでWidgetのさまざまなパターンのPreviewをまとめて確認できます!
もっといい方法や、他にも確認すべきパターンがあれば、コメントなどで教えていただけると嬉しいです :relaxed:

以上、 iOS Advent Calendar 2020 の10日目の記事でした。
明日は @MilanistaDev さんの記事です。

参考リンク

32
15
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
32
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?