Support External Display #osaka_swift

>100 Views

January 14, 25

スライド概要

Osaka.swift #1 で開催したクイズ大会の説明資料です。

profile-image

iOSアプリの開発をしています。 個人アプリも色々あります。 # Type: https://type-markdown.app WebCollector: https://webcollector.app/ Pity: https://freetimepicker.firebaseapp.com

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

Support External Display @fromkk

2.

• 阪 まれ、 阪育ち、今は埼 に住んでいます。 • 1986/02/20 県所沢市 まれ • @fromkk (X/note/Instagram/GitHub/ Zenn/Qiita etc…) 玉 生 大 己 2 生 自 大 紹介

3.

クイズアプリを作りました • 名前はQuiz Match • オーナーがクイズを作成 • メンバーは招待コードからクイズに参加すること ができる • 1.1.0からChatGPT経由でお題を作成できる ように 3

4.

外部ディスプレイ対応 • 前提: SwiftUIベース・TCA使 • @UIApplicationDelegateAdaptorでAppDelegate 対応 @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate: AppDelegate 用 4

5.

Info.plistにApplication Scene Manifestを追加 5

6.
[beta]
AppDelegateでSceneDelegateをサポート
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
if connectingSceneSession.role == .windowExternalDisplayNonInteractive {
return UISceneConfiguration(
name: "External Configuration",
sessionRole: connectingSceneSession.role)
} else {
return UISceneConfiguration(
name: "Default Configuration",
sessionRole: connectingSceneSession.role)
}
}

6

7.

SceneDelegateで外部ディスプレイの場合のUIを作成 import ComposableArchitecture import SwiftUI import UIKit final class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene( _ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions ) { guard let windowScene = scene as? UIWindowScene else { return } guard session.configuration.role == .windowExternalDisplayNonInteractive else { return } let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController( rootView: QuizExternalView( store: Store( initialState: QuizExternal.State() ) { QuizExternal() })) window.isHidden = false self.window = window } } 7

8.

困った点 • 本体側のViewと外部ディスプレイに表 る必要がある する内容を同期させ • 通常のSwiftUIなら@EnvironmentObjectを利 参考: https://useyourloaf.com/blog/swiftuisupporting-external-screens/ 用 示 8

9.

本体と外部ディスプレイのデータの同期 • TCAではSharing Stateが利 できそう 参考: https://pointfreeco.github.io/swiftcomposable-architecture/main/ documentation/composablearchitecture/ sharingstate/ • 1.17.0からはSharingが別パッケージに 用 9

10.
[beta]
実装
extension SharedReaderKey where Self == InMemoryKey<CurrentQuestion.State?> {
static var currentQuestion: Self {
inMemory("currentQuestion")
}
}

開催中のクイズ画

外部ディスプレイ

@Reducer
struct QuizOpening {
@ObservableState
struct State: Equatable, Sendable {
@Shared(.currentQuestion)
var currentQuestion: CurrentQuestion.State?

@Reducer
struct QuizExternal {
@ObservableState
struct State: Equatable, Sendable {
@SharedReader(.currentQuestion)
var currentQuestion: CurrentQuestion.State?
}

func setCurrentQuestion(_ currentQuestion: CurrentQuestion.State?) {
$currentQuestion.withLock {
$0 = currentQuestion
}
}
}

面

}

11.
[beta]
UIの 夫

• 外部ディスプレイのサイズは様々
• どのサイズでも同じように

えて欲しい

• GeometryReaderでサイズを取得し、基準となるサイズから
計算

var body: some View {
GeometryReader { context in
Text(currentQuestion.question.text)
.font(.system(size: 48 * aspect(context)))
.frame(maxWidth: .infinity, alignment: .leading)
}
}
private func aspect(_ context: GeometryProxy) -> CGFloat {
context.size.width / 1920
}

見

工

11

13.

まとめ • クイズアプリで外部ディスプレイ対応をしてみました • 本体と外部ディスプレイの同期にTCAのSharingを利 みました • UIの調整にはGeometryReaderを利 して計算 用 用 13 して

14.

大 ここからは@akidon0000作の クイズ 会🎉