WWDC22、iOS16：数行のコードで作成できるSwiftUIの新機能（26本）

:::note
※一般公開されているWWDC Keynoteの動画と公開Session/Documentation/Sample Codeページだけを使ってこの記事を執筆しました。
:::

新しいビューの種類:
[Gauge - 進捗状況を表示する新しいビュー](#gauge---進捗状況を表示する新しいビュー)
[複数日付選択ツール](#複数日付選択ツール)
[図表](#チャート)
[複数列のテーブル](#複数列のテーブル)
[グリッド(格子)表示](#グリッド格子で表示)
[貼り付けボタン](#貼り付けボタン)
[MacOS メニューバーアプリ](#macos-メニューバーアプリ)
[ナビゲーション・スタック](#ナビゲーションスタック)
[ナビゲーションのスプリットビュー](#ナビゲーションのスプリットビュー)

UIを変更する新しいビューモディファイア:
[グラデーションカラーを生成する](#グラデーションカラーを生成する)
[インナーシャドウ、アウターシャドウの追加](#インナーシャドウアウターシャドウの追加)

SwiftUIで直接利用（互換性のあるビューは不要になりました）。:
[共有シート](#共有シート)
[写真選択ツール](#写真選択ツール)
[アプリのレビューを依頼](#アプリのレビューを依頼)

機能の改善:
[サイズ変更可能なシート](#サイズ変更可能なシート)
[SF Symbolカラーバリエーション](#sf-symbolカラーバリエーション)
[複数行のテキストフィールド](#複数行のテキストフィールド)
[テキストフィールドを添付したアラート](#テキストフィールドを添付したアラート)
[スコープ選択で検索](#スコープ選択で検索)

新機能:
[ビューのスクリーンショット画像を取得する](#ビューのスクリーンショット画像を取得する)
[タップした位置の座標を取得](#タップした位置の座標を取得)
[ビューが表示されたときにテキストフィールドにフォーカスする](#ビューが表示されたときにテキストフィールドにフォーカスする)
[スクロール時にキーボードが自動的に解除される](#スクロール時にキーボードが自動的に解除される)
[リストに対する削除・移動アクションの自動生成](#リストに対する削除移動アクションの自動生成)
[MacOSで新しいウィンドウを追加して開く](#macosで新しいウィンドウを追加して開く)

その他の便利なコードスニペット:
[iOSのバージョンに応じた条件付きビューモディファイア](#iosのバージョンに応じた条件付きビューモディファイア)

お知らせ：beta1ではほとんどの機能が動作しますが、フォトピッカー、デフォルトフォーカスに一部不具合があります。

# 新しいビューの種類

## Gauge - 進捗状況を表示する新しいビュー

円形のゲージビュー (accessoryCircular) を使用して進捗状況を表示することができます。

### 特定の値(value)や範囲(in)を定義することです。また、`.tint`ビューモディファイアを使用すると、美しいグラデーションの色合いを追加することができます。

![gauge_with_color.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/77af4b56-95ce-c3ab-63c7-d11cb3171242.png)

```swift
Gauge(value: 23, in: 17...29) {
    Text("°C")
} currentValueLabel: {
    Text("23")
}
.gaugeStyle(.accessoryCircular)
.tint(Gradient(colors: [.green, .yellow, .orange]))
```

上記では、静的な値を使用しました。しかし、変数(`@State`など)を使用することができます。

### パーセント値（0から1まで）を使うこともできます。

```swift
Gauge(value: displayedProgress) {
    Text("%")
} currentValueLabel: {
    Text("\(Int(displayedProgress * 100))")
        .font(.caption)
}
.gaugeStyle(.accessoryCircular)
```

### ゲージのスタイルを指定しない場合、デフォルトで、通常のプログレスバーに似た線形ゲージが使用されます。

![default_gauge.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/0eb3abe5-7790-ad72-ca50-da1506628941.jpeg)

```swift
Gauge(value: displayedProgress) {
    Text("Default Gauge")
}
```

また、最小値位置／最大値位置／現在値位置のラベルを追加することも可能です。

![default_gauge_withvalues.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/992dc231-a272-e593-0234-ed7c90d26138.jpeg)

```swift
Gauge(value: 50, in: 0...100) {
    Text("Default Gauge")
} currentValueLabel: {
    Text("50%")
} minimumValueLabel: {
    Text("0%")
} maximumValueLabel: {
    Text("100%")
}
```

## 複数日付選択ツール

複数の日付を選択することができます。
タップすることで日付の選択・解除ができます。

![multi_date_picker.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/8f1b0003-801d-dee1-2608-6efcbcb0c471.jpeg)

```swift
struct MultipleDatePicker: View {
    
    @State private var userSelectedDates: Set<DateComponents> = []
    
    var body: some View {
        
        Form {
            MultiDatePicker("Select some dates", selection: $userSelectedDates)
            Section {
                Text("Selected dates:\(userSelectedDates.description)")
            }
        }
        
    }
    
}
```

## チャート

チャート（棒グラフ、折れ線グラフなど）を表示するには、Chartフレームワークを使用します。
以下の記事で紹介しています。

https://qiita.com/MaShunzhe/items/cae62af8b07f4f474fd8

## 複数列のテーブル

複数の列がある表を表示することができます。
これはiPadでのみ利用可能です。
iPhoneのポートレートモードで表示した場合、1列目のみが表示されます（Appleのエンジニアによると、iPhoneでは表はデフォルトでリストになるそうです）。

![20220608223332.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/668b1fea-6b31-10e5-3a10-d6a0327ad480.jpeg)

```swift
struct Table_MultiColumns: View {
    
    static let demoData: [MyPokemonFriend] = [
        .init(name: "Pika", species: "Pikachu", status: "Sleeping"),
        .init(name: "Zera", species: "Zeraora", status: "Charing my phone"),
        .init(name: "Luca", species: "Lucario", status: "Hiking")
    ]
    
    var body: some View {
        Table(Table_MultiColumns.demoData) {
            TableColumn("Name", value: \.name)
            TableColumn("Species", value: \.species)
            TableColumn("Status", value: \.status)
        }
    }
    
}
```

現在、beta1では、これに何らかの問題があるようです。タイトルがコンテンツと重なってしまう。

## グリッド(格子)で表示

グリッド(Grid)は、その名の通り、定義されたグリッドにアイテムを表示します。

![grid_demo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/daefc36f-90c2-89ac-6a28-67ba25299ec2.jpeg)

グリッド内の各ビュー要素では、`gridCellColumns`ビュー修飾子を使用して、1つのビュー要素が占めるスペースを定義することができます。例えば、1つのビュー要素が2つのビュー要素のスペースを占有したい場合、 `.gridCellColumns(2)` と定義します。

```swift
struct StaticGrid: View {
    var body: some View {
        Grid(horizontalSpacing: 20, verticalSpacing: 20) {
            GridRow {
                RoundedRectangle(cornerSize: .init(width: 20, height: 20))
                    .frame(width: 150, height: 150)
                    .foregroundColor(.blue)
                    .gridCellColumns(2) // this means this view element will be treated as 2 cell columns.
            }
            GridRow {
                RoundedRectangle(cornerSize: .init(width: 20, height: 20))
                    .frame(width: 150, height: 150)
                    .foregroundColor(.blue)
                RoundedRectangle(cornerSize: .init(width: 20, height: 20))
                    .frame(width: 150, height: 150)
                    .foregroundColor(.blue)
            }
        }
    }
}
```

## 貼り付けボタン

ユーザーのペーストボードにアクセスし、読み込むためのボタンです。
一般的には、データやオブジェクトのためのものです。
例えば、ユーザーがコピーした画像を読み込むためのボタンが考えられます。

![paste_button_demo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/4afcb242-d5ea-b781-12d9-ceec4923c88e.jpeg)

```swift
struct PasteButtonDemo: View {
    
    @State private var userPastedImageObj: UIImage?
    
    var body: some View {
        
        Form {
            
            PasteButton(supportedContentTypes: [.image]) { providers in
                if let firstProvider = providers.first {
                    _ = firstProvider.loadDataRepresentation(for: .image) { data, error in
                        if let data,
                           let imageObj = UIImage(data: data) {
                            self.userPastedImageObj = imageObj
                        }
                    }
                }
            }
            .buttonBorderShape(.capsule)
            
            if let userPastedImageObj {
                Image(uiImage: userPastedImageObj)
                    .resizable()
                    .scaledToFit()
            }
            
        }
        
    }
    
}
```

## MacOS メニューバーアプリ

SwiftUIアプリの中で`MenuBarExtra`を使用することで、簡単にMacOSのメニューバーアプリを作ることができるようになりました。

![20220608221528.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/f452d564-aadd-4c0e-bd65-73a777eaa40a.jpeg)

```swift
@main
struct TestMenuBarAppApp: App {
    var body: some Scene {
        MenuBarExtra {
            ContentView()
        } label: {
            Label("TODO", systemImage: "calendar.badge.clock")
        }
        .menuBarExtraStyle(.window)
    }
}
```

メニューバーアプリがウィンドウを表示している場合は、ビューモディファイア `. menuBarExtraStyle` を `.window` に設定することができます。また、メニューバーアプリがメニューを表示している場合は、`.menu`に設定することができます。

SwiftUI アプリ内で `MenuBarExtra` のみを使用する場合、メニューバーアイテムのみが表示されます。Dockにあるアプリのアイコンを隠したい場合は、`Info.plist`内で `LSUIElement` を `true` に設定します。

また、`MenuBarExtra` を `WindowGroup` に追加することで、アプリに通常のアプリウィンドウとメニューバーアイテムの両方を表示させることができます。

## ナビゲーション・スタック

```swift
struct NavigationStackDemo: View {
    
    var body: some View {
        
        NavigationStack {
            
            List {
                ForEach(pokemonObjs) { pokemon in
                    NavigationLink(pokemon.name, value: pokemon)
                }
            }
            .navigationDestination(for: Pokemon.self) { pokemon in
                PokemonDetailView(pokemonObj: pokemon)
            }
            
        }
        
    }
    
}
```

ここでは、`NavigationStack` を使用します。
各 `NavigationLink` には、ナビゲーションボタンを作成します。
`navigationDestination` モディファイアでは、各リストアイテムのビューを指定します。

## ナビゲーションのスプリットビュー

ナビゲーションの分割表示では、`detail`ブロックを使って詳細表示（ユーザーが左側の項目を選択すると右側に表示される）を行うことになります。

![navigation_split.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/c98d149c-4fc6-5db7-1363-fd2793358e5c.jpeg)

```swift
struct PartyPlannerHome: View {
    @State private var selectedTask: PartyTask?

    var body: some View {
        NavigationSplitView {
            List(PartyTask.allCases, selection: $selectedTask) { task in
                NavigationLink(value: task) {
                    TaskLabel(task: task)
                }
						    .listItemTint(task.color)
            }
        } detail: {
            selectedTask.flatMap { $0.color } ?? .white
        }
    }
}
```

# UIを変更する新しいビューモディファイア

## グラデーションカラーを生成する

SwiftUIの色に基づいてグラデーションを生成することができます。グラデーションは `.fill` のような場所で適用することができます。

![gradient_demo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/7f59b5f7-63f4-8a61-8a0e-4c54023ed59e.jpeg)

```swift
struct ColorGredientDemo: View {
    var body: some View {
        HStack {
            Rectangle()
                .fill(.blue.gradient)
                .frame(width:120, height:120)
            Rectangle()
                .fill(.orange.gradient)
                .frame(width:120, height:120)
            Rectangle()
                .fill(.green.gradient)
                .frame(width:120, height:120)
        }
    }
}
```

## インナーシャドウ、アウターシャドウの追加

![shadow_demo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/afdb0ef3-6ca5-15ab-1738-042d3f4f377c.jpeg)

影(シャドウ)は、シェイプの内側、または外側に付けることができます。

```swift
struct ShadowDemo: View {
    var body: some View {
        HStack {
            Rectangle()
                .fill(.blue.gradient.shadow(.inner(radius: 20)))
                .frame(width:120, height:120)
            Rectangle()
                .fill(.blue.gradient.shadow(.drop(radius: 20)))
                .frame(width:120, height:120)
        }
    }
}
```

# SwiftUIで直接利用（互換性のあるビューは不要になりました）

## 共有シート

以前は、SwiftUIでシステムの共有シートでアイテムを共有するには、UIActivityViewControllerを使用する必要がありました。今では、`ShareLink`ビューコンポーネントを使うことで、共有シートを提示することができます。

![SWIFTUI-SHAREPLAY.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/12a42948-c988-31a1-a380-9621151c3dc5.jpeg)

```swift
struct ShareLink_sharing_sheet: View {
    var body: some View {
        Form {
            ShareLink("Share our URL", item: "View all SwiftUI components at https://ui.mszpro.com", preview: SharePreview("SwiftUI view components"))   
        }   
    }   
}
```

文字列、画像、データ、URLなどのデータ型の共有ができるはずです。

## 写真選択ツール

(この機能は、ベータ1ではシミュレータで実行した場合、いくつかの問題があるようです。フォトピッカーは表示されますが、写真を選択しても何も起こりません)。

![photo_picker.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/523f3a3c-fc8c-6712-797d-4749726f1318.jpeg)

```swift
struct PhotosPicker_Demo: View {
    
    @State private var selectedImage: PhotosPickerItem?
    @State private var newlyPickedImage: UIImage?
    
    var body: some View {
        
        Form {
            
            PhotosPicker("Pick a new background image", selection: $selectedImage, matching: .images)
                .onChange(of: selectedImage) { newValue in
                    if let newValue {
                        newValue.loadTransferable(type: Data.self) { result in
                            switch result {
                                case .success(let success):
                                    if let success,
                                       let imageObj = UIImage(data: success)
                                    {
                                        self.newlyPickedImage = imageObj
                                    }
                                case .failure(let failure):
                                    return
                            }
                        }
                    }
                }
            
            if let newlyPickedImage {
                Image(uiImage: newlyPickedImage)
                    .resizable()
                    .scaledToFit()
            }
            
        }
        
    }
    
}
```

## アプリのレビューを依頼

これで、環境変数を使ってSwiftUI内で簡単にアプリのレビューを要求できるようになりました。

```swift
import SwiftUI
import StoreKit

struct RequestAppReview: View {
    
    @Environment(\.requestReview) var requestReview

    var body: some View {
        Button("Request review") {
            requestReview()
        }
    }
    
}
```

SwiftUI では、アプリのレビューを要求する通常の関数 (`SKStoreReviewController.requestReview(in: <#T##UIWindowScene#>)`) はウィンドウシーンの入力が必要なので、これは便利です。

# 機能の改善

## サイズ変更可能なシート

これで、様々なデテント（中、大、カスタムサイズ）でシートを表示し、ユーザーがドラッグしてシート全体を表示させることができます。

![resizable_sheet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/37b10e9f-1760-c10e-72b4-3f0456d6bc83.jpeg)

```swift
struct Resizable_sheets: View {
    
    @State private var showSheet: Bool = false
    
    var body: some View {
        
        Button("Present sheet") {
            self.showSheet = true
        }
            .sheet(isPresented: $showSheet) {
                Text("Hello world!")
                    .presentationDetents([.medium, .large])
            }
        
    }
    
}
```

## SF Symbolカラーバリエーション

例えば、信号の強さを表すのに使用することができます。

![varied_sfsymbol.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/975d8072-53f5-456f-67e1-e2ffa8728f94.jpeg)

```swift
struct SFSymbol_variedColor: View {
    
    @State private var wifiSignalStrength: Double = 1.0
    
    var body: some View {
        
        Form {
            
            Image(systemName: "wifi", variableValue: wifiSignalStrength)
            
            Slider(value: $wifiSignalStrength, in: 0...1)
            
        }
        
    }
    
}
```

## 複数行のテキストフィールド

SwiftUIのテキストフィールドが複数行をサポートするようになりました。縦に展開されます。

![textfield:multiline.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/ebbf01e5-481b-7c2c-c974-7e9e12352c3c.jpeg)

```swift
TextField("Enter some text here", text: $userEnteredText, axis: .vertical)
```

また、`lineLimit`ビューモディファイアを使用すると、行数を制限することができます。

## テキストフィールドを添付したアラート

アラート内にテキストフィールドを追加できるようになりました。
ユーザーが入力した内容は、`@Binding`を使用して変数に更新されます。

![card-reading-demo-img-1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/77f92d2a-a3c6-a7db-647c-751f9408969c.jpeg)

`.alert`ビューモディファイア宣言の後に要素のブロックを追加することになります。

```swift
struct Alert_with_TextField: View {
    
    @State private var typedPasscode: String = ""
    @State private var showPasscodeAlert: Bool = false
    
    var body: some View {
        
        Form {
            Button("Enter passcode and NFC scan") {
                self.typedPasscode = ""
                self.showPasscodeAlert = true
            }
            .alert("Enter card passcode", isPresented: $showPasscodeAlert) {
                TextField("Passcode", text: $typedPasscode)
                Button("Confirm") {
                    print(typedPasscode)
                }
                Button("Cancel", role: .cancel, action: {})
            }
        }
        
    }
    
}
```

## スコープ選択で検索

スコープを選択した検索ビューを提供することができます。

```swift
List(filteredResults) { result in
    Text(result.name)
}
.searchable(text: $searchText, scope: $searchScope) {
    ForEach(SearchScope.allCases, id: \.self) { scope in
        Text(scope.rawValue)
    }
```

# 新機能

## ビューのスクリーンショット画像を取得する

SwiftUIのビューを画像にレンダリングすることができるようになりました。

いくつかのコントロールビュー（ステッパーのようなユーザーインタラクティブビュー）はレンダリングできないことに注意してください。レンダリングできないビューには、×印が表示されます。(beta1では)

```swift
struct Render_view_toImage: View {
    
    @State private var currentProgressValue: Double = 0
    @State private var renderedImage: UIImage?
    
    var body: some View {
        
        Form {
            
            gauge_experimentation_view
            
            Section {
                Button("Save view to image") {
                    let renderer = ImageRenderer(content: gauge_experimentation_view)
                    if let image = renderer.uiImage {
                        self.renderedImage = image
                    }
                }
            }
            
            Section {
                if let renderedImage {
                    Image(uiImage: renderedImage)
                }
            }
            
        }
        
    }
    
    var gauge_experimentation_view: some View {
        Section {
            Gauge(value: self.currentProgressValue, in: 0...100) {
                Text("Default Gauge")
            } currentValueLabel: {
                Text("\(currentProgressValue)%")
            } minimumValueLabel: {
                Text("0%")
            } maximumValueLabel: {
                Text("100%")
            }
            Stepper("Gauge value", value: $currentProgressValue, in: 0...100, format: .number)
        }
    }
    
}
```

## タップした位置の座標を取得

ユーザーのタップジェスチャーを検出する `onTap` ジェスチャーを使用した場合、ユーザーがタップした場所を取得できるようになりました。

```swift
struct OnTap_Gesture_Location: View {
    var body: some View {
        Form {
            Rectangle()
                .fill(.blue)
                .frame(width: 300, height: 500)
                .onTapGesture(coordinateSpace: .local) { tappedLocation in
                    print(tappedLocation)
                }
        }
    }
}
```

上の例ではローカル(local)座標空間を使いましたが、これは矩形に対する相対的な座標を意味します。画面に対する相対的な座標を得るためにグローバル(global)座標空間を使うこともできる。

## ビューが表示されたときにテキストフィールドにフォーカスする

(この機能は、beta1のXcodeシミュレータでは動作しないようです。具体的には、ビューが表示されたときにテキストフィールドが選択されていないのです)。

ビューが表示されたときに特定のテキストフィールドにフォーカスを当てるようにSwiftUIに要求できるようになりました。まず、`@FocusState`変数を追加する必要があります。それから、`defaultFocus`ビューモディファイアを使います。

```swift
WindowGroup {
    VStack {
        TextField(...)
            .focused($focusedField, equals: .firstField)
        TextField(...)
            .focused($focusedField, equals: .secondField)
    }
    .defaultFocus($focusedField, .secondField)
}
```

## スクロール時にキーボードが自動的に解除される

```swift
struct ScrollDismissKeyboardDemo: View {
    @State private var userEnteredText: String = ""
    var body: some View {
        Form {
            TextField("Text entry", text: $userEnteredText)
                .scrollDismissesKeyboard(.interactively)
        }
        .scrollIndicators(.hidden)
    }
}
```

## リストに対する削除・移動アクションの自動生成

さて、Listに配列を表示する場合、SwiftUIに移動アクションと削除ボタンを自動的に生成するように依頼することができます。これにより配列が直接更新されます。

![automatic_list:actions.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/aea09e32-65a9-048a-7fec-eba043ad560d.jpeg)

変数が変更されたときに、変更されたデータをデータベースに更新するために `.onChange` を使用する必要があるかもしれません。

```swift
struct AutomaticListEditActions: View {
    
    @State var items = ["Item 1", "Item 2", "Item 3"]
    
    var body: some View {
        Form {
            List($items, id: \.self, edits: [.delete, .move]) { $item in
                Text(item)
            }
            Text(items.joined(separator: ","))
        }
    }
    
}
```

## MacOSで新しいウィンドウを追加して開く

SwiftUIを使って、MacOSアプリに新しいウィンドウを追加することができます。また、ウィンドウを表示するためのキーボードショートカットを定義することができます。

![window_demo.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/c5253011-2b6b-9223-f6e1-b9199b6b832c.jpeg)

SwiftUIのアプリファイルで`Window`ビューコンポーネントを定義することによって、それを行います。

```swift
@main
struct WindowsNewTestingApp: App {
    var body: some Scene {
        WindowGroup("Main View") {
            ContentView()
        }
        
        Window("New window", id: "new_window") {
            Text("New window here!")
        }
        .keyboardShortcut("0")
        .defaultPosition(.topLeading)
        .defaultSize(width: 220, height: 250)
    }
}
```

上記の例では、キーボードショートカットを "0 "キーと定義しています。
これは、commandキーと0キーを意味します。

また、`defaultPosition`ビューモディファイアを使ってデフォルトの位置を定義したり、`defaultSize`ビューモディファイアを使ってデフォルトのサイズを定義したりすることができます。

アプリ内では、そのウィンドウを開くためのボタンも定義することができます。

```swift
struct DetailView: View {
    @Environment(\.openWindow) var openWindow

    var body: some View {
        Text("Detail View")
            .toolbar {
                Button {
                    openWindow(id: "new_window")
                } label: {
                    Image(systemName: "dollarsign")
                }
            }
    }
}
```

Windowビューコンポーネントを作成する際に、そのidを`new_window`と定義しています。そのウィンドウをボタンで開きたい場合は、`openWindow`関数に開きたいウィンドウのidを指定して使用します。

# その他の便利なコードスニペット

## iOSのバージョンに応じた条件付きビューモディファイア

iOS 16では、多くの新しいビューモディファイアが利用できるようになりました。システムのバージョンに応じて条件付きでモディファイアを使用したい場合。以下のコードを使用することができます。

```swift
let common = commonViewParts
if #available(iOS 16.0, macOS 13.0, *) {
    return common.newModifier()
} else {
    return common.oldModifier()
}
```

---


:thumbsup: お読みいただきありがとうございました。

[☺️ Twitter @MszPro](https://twitter.com/MszPro)
[🐘 Mastodon @me@mszpro.com](https://sns.mszpro.com/@me)

:sunny: <img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">

---
![writing-quickly_emoji_400.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/640938e9-c121-8152-b8c4-8ab63124afcc.png)


# 関連記事

・[UICollectionViewの行セル、ヘッダー、フッター、またはUITableView内でSwiftUIビューを使用（iOS 16, UIHostingConfiguration）](https://qiita.com/MaShunzhe/items/3d98fa897aa1bcffc74b#github-repository)

・[iPhone 14 ProのDynamic Islandにウィジェットを追加し、Live Activitiesを開始する（iOS16.1以降）](https://qiita.com/MaShunzhe/items/6cc8d9d204f40cbee19c)

・[iOS 16：秘密値の保存、FaceID認証に基づく個人情報の表示/非表示（LARight）](https://qiita.com/MaShunzhe/items/07c1e65277a5008106db)

・[iOS16 MapKitの新機能 : 地図から場所を選ぶ、通りを見回す、検索補完](https://qiita.com/MaShunzhe/items/693e6302876707d5684d)

・[SwiftUIアプリでバックグラウンドタスクの実行(ネットワーク、プッシュ通知) (BackgroundTasks, URLSession)](https://qiita.com/MaShunzhe/items/4e0d1032748fe4f398de)

・[WWDC22、iOS16：iOSアプリに画像からテキストを選択する機能を追加（VisionKit）](https://qiita.com/MaShunzhe/items/ed3985d05975bf35292d)

・[WWDC22、iOS16：数行のコードで作成できるSwiftUIの新機能（26本）](https://qiita.com/MaShunzhe/items/0ed36d8a6de7c56b1d34)

・[WWDC22、iOS 16：SwiftUIでChartsフレームワークを使ってチャートを作成する](https://qiita.com/MaShunzhe/items/cae62af8b07f4f474fd8)

・[WWDC22, iOS 16: WeatherKitで気象データを取得](https://qiita.com/MaShunzhe/items/dce45ccdd05c1f70cf54)

・[WWDC 2022の基調講演のまとめ記事](https://qiita.com/MaShunzhe/items/037580d2ed51a5a6e9d9)