2023/10/5
Apple Vision Pro (visionOS) の SwiftUIでhoverEffectを実装する
はじめに
Apple Vision Pro の Windowアプリにおいて、アイトラッキングによる視線に対してホバーの状態をビジュアルで表現するための実装について説明します。
Apple Vision Pro について
Apple Vision Pro について、以下の記事にまとめてます。
Windowプロジェクト
Initial SceneをWindowを選択してvisionOSプロジェクトを作成します。
使用したアイコン
https://www.svgrepo.com/collection/fitness-and-health-food-vectors/
上記の任意のフルーツのSVGファイルをダウンロードします。ダウンロードしたSVGファイルをXcodeで作成したvisionOSプロジェクトのAssetsにドラッグ&ドロップします。
RectFruitButton.swift
import SwiftUI
struct RectFruitButton: View {
@State var name:String
@State var action: (_ tap:String) -> Void
@State private var tap: Bool = false
var body: some View {
Image(name)
.resizable()
.frame(width: 120, height: 120)
.padding(.all, 20)
.background(.fill.tertiary, in: .rect(cornerRadius: 24))
.contentShape(.hoverEffect, .rect(cornerRadius: 24))
.scaleEffect(self.tap ? 1.5 : 1)
.onTapGesture {
self.tap.toggle()
action(self.tap ? "ON" : "OFF")
}
.hoverEffect()
}
}
四角形のフルーツのImageを実装します。ホバーしている間はビジュアルで表現したいため、.hoverEffectを設定しています。backgroundの形に合わせてcontentShapeでホバー時の形を合わせています。
CircleFruitButton.swift
import SwiftUI
struct CircleFruitButton: View {
@State var name:String
@State var action: (_ tap:String) -> Void
@State private var tap: Bool = false
var body: some View {
Image(name)
.resizable()
.frame(width: 120, height: 120)
.padding(.all, 20)
.background(.fill.tertiary, in: .circle)
.contentShape(.hoverEffect, .circle)
.scaleEffect(self.tap ? 1.5 : 1)
.onTapGesture {
self.tap.toggle()
action(self.tap ? "ON" : "OFF")
}
.hoverEffect()
}
}
backgroundとcontentShapeを.circleで設定している所以外、RectFruitButton.swiftと同じです。
ContentView.swift
import SwiftUI
struct ContentView: View {
@State var name:String
var body: some View {
VStack(spacing: 100) {
HStack(spacing: 100) {
RectFruitButton(name: "grape", action: { tap in self.name = "rect grape \(tap)" })
RectFruitButton(name: "lemon", action: { tap in self.name = "rect lemon \(tap)" })
RectFruitButton(name: "peach", action: { tap in self.name = "rect peach \(tap)" })
}
HStack(spacing: 100) {
CircleFruitButton(name: "grape", action: { tap in self.name = "circle grape \(tap)" })
CircleFruitButton(name: "lemon", action: { tap in self.name = "circle lemon \(tap)" })
CircleFruitButton(name: "peach", action: { tap in self.name = "circle peach \(tap)" })
}
Text(name).font(.extraLargeTitle)
}
}
}
RectFruitButtonとCircleFruitButtonを縦2行、横3列で並べています。
実行
カーソルを合わせると、ホバーします。RectとCircleの形に合わせて、違和感なく状態が変化します。タップすると、スケールが変わり、スケールにあったホバー状態になります。
XR エンジニア
徳山 禎男
SIerとして金融や飲料系など様々な大規模プロジェクトに参画後、2020年にOnePlanetに入社。ARグラスを中心とした最先端のAR技術のR&Dや、法人顧客への技術提供を担当。過去にMagic Leap 公式アンバサダーを歴任。
View More