スワイプを実装方法
1.TabView を実装
2.DragGesture() をカスタムして実装
TabViewを使用
メリット
✅ デフォルトでスワイプ対応
• .tabViewStyle(PageTabViewStyle()) を指定するだけで、スワイプでページ遷移が可能。
✅ アニメーションが自動適用
• TabView は ページ間のスワイプアニメーションが自動で適用される。
✅ シンプルなコード
• TabView に .tag() を設定するだけでページ管理が可能。
デメリット
❌ 自由なカスタマイズが難しい
• TabView のスワイプアニメーションを カスタマイズするのは難しい。
❌ プログラム的なページ切り替えがやや面倒
• currentPage を tag で管理する必要がある。
❌ スワイプが有効な範囲が制限される
• TabView は画面 全体のスワイプ しかサポートしないため、一部の領域だけでスワイプを有効にするのが難しい。
import SwiftUI
struct Tab_View: View {
@State private var currentPage: Page = .home
var body: some View {
TabView(selection: $currentPage) {
Tab_HomeView(currentPage: $currentPage)
.tag(Page.home)
Page3View(currentPage: $currentPage)
.tag(Page.page1)
Page4View(currentPage: $currentPage)
.tag(Page.page2)
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always)) // スワイプでページ切り替え
}
}
struct Tab_HomeView: View {
@Binding var currentPage: Page
var body: some View {
VStack {
Text("たぶViewホーム画面")
.font(.largeTitle)
.padding()
}
}
}
struct Page3View: View {
@Binding var currentPage: Page
var body: some View {
VStack {
Text("Page 1")
.font(.largeTitle)
Button("ホームに戻る") {
currentPage = .home
}
.padding()
}
}
}
struct Page4View: View {
@Binding var currentPage: Page
var body: some View {
VStack {
Text("Page 2")
.font(.largeTitle)
Button("ホームに戻る") {
currentPage = .home
}
.padding()
}
}
}
#Preview {
Tab_View()
}
DragGesture()を使用
メリット
✅ 自由にカスタマイズ可能
• スワイプ感度、スワイプの方向、スワイプ距離 などを自由に設定できる。
✅ スワイプが有効な領域を調整できる
• contentShape(Rectangle()) などを使えば、 画面全体ではなく、一部の領域だけスワイプを有効にすることが可能。
✅ ページの制御がしやすい
• currentPage の変更だけでページを管理できる。
デメリット
❌ アニメーションが自動でつかない
• TabView のように スムーズなスワイプアニメーションはデフォルトで適用されない ため、カスタムで withAnimation を適用する必要がある。
❌ ページ数が多いとコードが複雑になる
• switch currentPage { ... } のような ページ管理コードが増えてしまう。
import SwiftUI
enum Page {
case home, page1, page2
}
struct ContentView: View {
@State private var currentPage: Page = .home
var body: some View {
ZStack {
currentPageView()
.gesture(
DragGesture()
.onEnded { value in
if value.translation.width < -100 { // 左スワイプ
goToNextPage()
} else if value.translation.width > 100 { // 右スワイプ
goToPreviousPage()
}
}
)
}
}
func currentPageView() -> some View {
switch currentPage {
case .home:
return AnyView(Tab_HomeView(currentPage: $currentPage))
case .page1:
return AnyView(Page1View(currentPage: $currentPage))
case .page2:
return AnyView(Page2View(currentPage: $currentPage))
}
}
func goToNextPage() {
switch currentPage {
case .home:
currentPage = .page1
case .page1:
currentPage = .page2
case .page2:
break // 何もしない(最後のページ)
}
}
func goToPreviousPage() {
switch currentPage {
case .home:
break // 何もしない(最初のページ)
case .page1:
currentPage = .home
case .page2:
currentPage = .page1
}
}
}
struct HomeView: View {
@Binding var currentPage: Page
var body: some View {
VStack {
Text("ホーム画面")
.font(.largeTitle)
List {
Text("大根")
Text("キャベツ")
Text("じゃがいも")
}
}
}
}
struct Page1View: View {
@Binding var currentPage: Page
var body: some View {
VStack {
Text("Page 1")
.font(.largeTitle)
Button("ホームに戻る") {
currentPage = .home
}
.padding()
}
}
}
struct Page2View: View {
@Binding var currentPage: Page
var body: some View {
VStack {
Text("Page 2")
.font(.largeTitle)
Button("ホームに戻る") {
currentPage = .home
}
.padding()
}
}
}
#Preview {
ContentView().environmentObject(UserSettings())
}