Swift・iOS

Swiftを中心に学んだことを記録に残すブログです。技術に関係ない記事もたまに書いています。

【SwiftUI】Listの各行ごとに別のモーダルビュー(sheet)を表示する

 

はじめに

【SwiftUI】ListからNavigationLinkで画面遷移する - Swift・iOSの続きです。今回はListからモーダルビューへ画面遷移する実装を試したので記事に残します。

 

開発環境

 

サンプルイメージ 

f:id:hfoasi8fje3:20210328195453g:plain

 

実装

SettingView.swift

import SwiftUI

struct SettingView: View {
    @ObservedObject private var viewModel: SettingViewModel
    
    init(viewModel: SettingViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        VStack(alignment: .leading) {
            Text("設定")
                .font(.title)
                .bold()
                .padding([.leading, .trailing, .top], 25)
            
            List {
                ForEach(viewModel.settings) { setting in
                    Section(header: Text(setting.header)) {
                        ForEach(setting.settingTitles) { titles in
                            Text(titles.title)
                                .onTapGesture {
                                    viewModel.selectedSettingTitle = SettingViewModel.SettingTitleType(rawValue: titles.title) ?? .other
                                    viewModel.isModalActive.toggle()
                                }
                                .sheet(isPresented: $viewModel.isModalActive) {
                                    switch viewModel.selectedSettingTitle {
                                    case .edit:
                                        Text("編集")
                                    case .privacy:
                                        Text("プライバシーポリシー")
                                    case .license:
                                        Text("ライセンス")
                                    case .version:
                                        Text("バージョン")
                                        
                                    default:
                                        Text("その他")
                                    }
                                }
                        }
                    }
                }
            }
            .listStyle(InsetGroupedListStyle())
        }
    }
}

 

SettingViewModel.swift

import Foundation

class SettingViewModel: ObservableObject {
    @Published var isModalActive = false
    var selectedSettingTitle: SettingTitleType = .other
    
    struct SettingTitle: Hashable, Identifiable {
        var id = UUID()
        var title : String
    }
    
    struct Setting: Identifiable {
        var id = UUID()
        var header: String
        var settingTitles: [SettingTitle]
    }
    
    var settings: [Setting] = [
        Setting(header: "ブックマーク",
                settingTitles: [SettingTitle(title: "編集")]),
        Setting(header: "その他",
                settingTitles: [SettingTitle(title: "プライバシーポリシー"),
                                SettingTitle(title: "ライセンス"),
                                SettingTitle(title: "バージョン")])
    ]
    
    enum SettingTitleType: String {
        case edit = "編集"
        case privacy = "プライバシーポリシー"
        case license = "ライセンス"
        case version = "バージョン"
        case other
    }
}

 

SceneDelegate.swift

実際にサンプルコードを動かしてみたい場合は、SceneDelegate.swiftの"scene(_:willConnectTo:options:)"を以下のように変更してください。

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    let viewModel = SettingViewModel()
    let settingView = SettingView(viewModel: viewModel)

    if let windowScene = scene as? UIWindowScene {
        let window = UIWindow(windowScene: windowScene)
        window.rootViewController = UIHostingController(rootView: settingView)
        self.window = window
        window.makeKeyAndVisible()
    }
}

 

おわりに

実装としても挙動しても改善の余地がありそうと思いつつ、やったことを一旦記事に残しました。

挙動としては、現状Listに表示された各項目(文字列)を選択しないとモーダルが表示されないため、Listの行を選択しても画面遷移できるNavigationLinkと比較すると、ユーザー側としては使いにくそうです。

Listからの画面遷移は基本NavigationLinkを使用したほうが実装がシンプルかつ使い勝手もよくなると感じました。

 

参考