0
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 で Slack の様なサイドバーを作る

Last updated at Posted at 2021-07-28

こんな感じです。
side-gif2.gif

import SwiftUI

struct ContentView: View {

    @State private var offset = CGFloat.zero
    @State private var initialOffset = CGFloat.zero

    @State private var isCoverPresent = false
    @State private var isSidebarPresent = false

    @State private var displayWidth = CGFloat.zero
    private var sidebarWidth:CGFloat { displayWidth * 0.85 }
    
    @State private var animation = Animation.linear(duration: 0.1)

    func openSidebar() {
        offset = .zero
        initialOffset = offset
        isSidebarPresent = true
    }

    func closeSidebar() {
        offset = -sidebarWidth
        initialOffset = offset
        isSidebarPresent = false
    }

    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0) {

                SidebarView()
                    .frame(width: sidebarWidth)

                ZStack {
                    Text("右にスワイプでサイドバーを開く")
                        .frame(width: displayWidth, height: geometry.size.height) // VStack の高さを画面いっぱいにして onTapGesture するようにする
                        .background(Color.orange)

                    if isCoverPresent {
                        Color.black
                            .opacity(Double((1 + self.offset / sidebarWidth) * 0.6))
                            .onTapGesture { withAnimation(animation) { closeSidebar() } }
                    }
                }
            }
            .offset(x: offset)
            .onAppear {
                displayWidth = geometry.size.width
                closeSidebar()
            }
            .gesture(DragGesture(minimumDistance: 1) // minumumDistance: 0 にすると、サイドバーやメイン画面の Button が反応しなくなるので 1 を設定
                .onChanged{ value in
                    // サイドバーが右に行きすぎていないなら
                    if (self.offset <= CGFloat.zero) {
                        offset = initialOffset + value.translation.width
                        isCoverPresent = true
                    }
                }
                .onEnded { value in
                    withAnimation(animation) {
                        if isSidebarPresent {
                            // 左にスワイプしたら
                            if value.location.x < value.startLocation.x - displayWidth * 0.1 {
                                closeSidebar()
                            } else {
                                openSidebar()
                            }
                        } else {
                            // 右にスワイプしたら
                            if value.location.x > value.startLocation.x + displayWidth * 0.2 {
                                openSidebar()
                            } else {
                                closeSidebar()
                            }
                        }
                    }
                }
            )
        }
    }
}

fileprivate struct SidebarView: View {
    var body: some View {
        Text("サイドバー")
            .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
            .background(Color.blue)
            .foregroundColor(.white)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
0
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
0
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?