1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SwiftUIでページ遷移(上部)を実装する

Last updated at Posted at 2021-04-12

参考

【iOS】遷移方法まとめとエンジニア1年生の独り言
上部左右から出現するメニューを作る
SwiftUIのGestureについてまとめ

画面遷移について

  1. モーダル ... 下から画面が出現
  2. プッシュ ... 右から画面が出現
  3. タブ ... 瞬時の切り替わり(タブアイテムのタップ)
  4. ページ ... 左右から画面が出現(左右スワイプ) ※サイドメニューと同義

ページ遷移(上部)の実装

写真

IMG_0954.jpg

動画

コード

ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var showingModal = false
    
    @State private var offset = CGFloat.zero    // 現在のオフセット
    @State private var closeOffset = CGFloat.zero   // 閉状態のオフセット
    @State private var openOffset = CGFloat.zero    // 開状態のオフセット
   
    var body: some View {
        GeometryReader { geometry in
            ZStack {
                // メインコンテンツ
                VStack {
                    Button("Show ModalView.") {
                        self.showingModal.toggle()
                    }.sheet(isPresented: $showingModal) {
                        ModalView()
                    }
                    
                    Divider()
                    
                    NavigationView {
                        NavigationLink(destination: PushView()) {
                            Text("Show PushView.")
                        }.navigationBarTitle("ContentView", displayMode: .automatic)
                    }
                    
                    Divider()
                    
                    TabView {
                        TabAView()
                            .tabItem {
                                Image(systemName: "moon")
                                Text("Tab A")
                            }
                        
                        TabBView()
                            .tabItem {
                                Image(systemName: "moon.fill")
                                Text("Tab B")
                            }
                    }
                }
                // 上部メニュー
                PageUpView()
                    .background(Color.gray)
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    // View描画時に呼び出すメソッド
                    .onAppear(perform: {
                        // PageUpViewのオフセット初期値として負の方向(上方向)に[Safe Areaの高さ]+[PageUpView自体の高さ]分ずらす
                        self.offset = -1 * (geometry.frame(in: .global).origin.y + geometry.size.height)
                        // 閉状態のオフセット = 初期状態のオフセット
                        self.closeOffset = self.offset
                        // 開状態のオフセット = 0
                        self.openOffset = .zero
                    })
                    // オフセット
                    .offset(y: self.offset)
                    // アニメーション
                    .animation(.default)
            }
            //ジェスチャーに関する実装
            .gesture(DragGesture(minimumDistance: 5)
                        // DragGestureの入力開始時の呼び出しメソッド
                        .onChanged { value in
                            // ContentViewの現在のオフセットが初期値でない かつ DragGestureの開始位置のy座標が30未満の場合
                            if (self.offset != self.openOffset && value.startLocation.y < 30) {
                                // ContentViewの現在のオフセット = 初期状態からy軸方向にDragされた距離
                                self.offset = self.closeOffset + value.translation.height
                            }
                        }
                        // DragGestureの入力終了時の呼び出しメソッド
                        .onEnded { value in
                            //Gesture終了時のViewのy座標がGesture開始時よりも高い(Viewが下方向に動いた場合)
                            if (value.startLocation.y < value.location.y) {
                                // Gestureの開始位置のy座標が30未満の場合
                                if (value.startLocation.y < 30) {
                                    // PageUpViewを開状態にする
                                    self.offset = self.openOffset
                                }
                            } else {
                                // PageUpViewを閉状態にする
                                self.offset = self.closeOffset
                            }
                        }
            )
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
PageUpView.swift
import SwiftUI

struct PageUpView: View {
    var body: some View {
        Text("This is Up Side.")
    }
}

struct PageUpView_Previews: PreviewProvider {
    static var previews: some View {
        PageUpView()
    }
}

学習結果

GeometryReader

自身のViewサイズと座標空間を返す関数をクロージャとして保持するView。
GeometryReaderを通じて自身のView(.local)やRootView(.global)のサイズ、座標位置を取得することができる。

onAppear修飾子

Viewが初めて描画されるタイミングで呼び出されるメソッド。

onDisappear修飾子

Viewが非表示になるタイミングで呼び出されるメソッド。

Gestureの種類

  • TapGesture
    → タップ
  • LongPressGesture
    → 長押し
  • DragGesture
    → ドラッグ
  • MagnificationGesture
    → ピンチ
  • RotationGesture
    → 回転

gesture修飾子

Viewに対してジェスチャーが入力されたときの呼び出しメソッドを実装する。

GestureのCallback処理

  • updating
    → Gestureの値が更新された際に発火(UIの一時的な状態変更)
  • onChanged
    → Gestureの値が更新された際に発火(UIの恒久的な状態変更)
  • onEnded
    → Gestureが終了した際に発火
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?