SwiftUI에서 슬라이드할 때 숨겨진 버튼을 표시하는 보기를 만드는 방법

21369 단어 iosswiftui

소개



이 문서에서는 보기를 왼쪽으로 슬라이드할 때 오른쪽에서 숨겨진 버튼이 나타나는 SwiftUI에서 보기를 구현하는 방법을 소개합니다.



구현



이는 사용자가 보기를 드래그할 때 보기의 x축 오프셋을 변경하여 수행할 수 있습니다.

Xcode의 Playground에서 실행 가능한 코드는 다음과 같습니다.

import SwiftUI
import PlaygroundSupport

struct ContentView: View {
    var body: some View {
        VStack(spacing: 0) {
            SlideButtons()
                .frame(width: 300, height: 40)
            SlideButtons()
                .frame(width: 300, height: 40)
            SlideButtons()
                .frame(width: 300, height: 40)
        }
    }
}

struct SlideButtons: View {
    // The current x offset of the view.
    @State private var xOffset = CGFloat.zero

    // The default x offset when a drag ends.
    @State private var defaultXOffset = CGFloat.zero

    // Initialize it on `.onAppear()`.
    @State private var hiddenButtonWidth: CGFloat = 0

    @State private var hiddenButtonMaxWidth: CGFloat = 50

    // Ratio of a hidden button width to the entire View.
    private let buttonSizeRatio = 6

    private var dragGesture: some Gesture {
        DragGesture(minimumDistance: 30, coordinateSpace: .local)
            .onChanged { value in
                self.xOffset += value.translation.width
                if self.hiddenButtonMaxWidth * -2 <= self.xOffset && self.xOffset <= 0 {
                    self.hiddenButtonWidth = min(self.xOffset / -2, self.hiddenButtonMaxWidth)
                }
            }
            .onEnded { value in
                withAnimation() {
                    if self.areHiddenButtonsShowed() {
                        if (self.xOffset - self.defaultXOffset) > self.getMinDistanceToChangeDefaultXOffset() {
                            self.hideButtons()
                        } else {
                            // Return to the current default position.
                            self.xOffset = self.defaultXOffset
                            // Reset the button size
                            self.hiddenButtonWidth = self.hiddenButtonMaxWidth
                        }

                    } else {
                        if (self.defaultXOffset - self.xOffset) > self.getMinDistanceToChangeDefaultXOffset() {
                            self.showHiddenButtons()
                        } else {
                            // Return to the current default position.
                            self.xOffset = self.defaultXOffset
                            // Reset the button size
                            self.hiddenButtonWidth = 0
                        }
                    }
                }
            }
    }

    var body: some View {
        GeometryReader { geometry in
            HStack(spacing: 0) {
                // Main button
                Rectangle()
                    .foregroundColor(.black)
                    .overlay {
                        HStack {
                            Text("Read a book")
                                .foregroundColor(.white)
                                .padding()
                            Spacer()
                        }
                    }
                    .frame(width: geometry.size.width,
                           height: geometry.size.height)
                    .gesture(
                        self.dragGesture
                    )
                    .onTapGesture {
                        withAnimation() {
                            if self.areHiddenButtonsShowed() {
                                self.hideButtons()
                            } else {
                                self.showHiddenButtons()
                            }
                        }
                    }

                // 1st hidden button
                Rectangle()
                    .frame(width: self.hiddenButtonWidth, height: geometry.size.height)
                    .foregroundColor(Color.yellow)
                    .overlay {
                        Text("Skip")
                            .foregroundColor(.white)
                    }

                // 2nd hidden button
                Rectangle()
                    .frame(width: self.hiddenButtonWidth, height: geometry.size.height)
                    .foregroundColor(Color.red)
                    .overlay {
                        Text("Done")
                            .foregroundColor(.white)
                    }
            }
            .onAppear() {
                self.hiddenButtonWidth = 0
                self.hiddenButtonMaxWidth = geometry.size.width / CGFloat(self.buttonSizeRatio)
                self.hideButtons()
            }
            .frame(width: geometry.size.width, height: geometry.size.height, alignment: .leading)
            .offset(x: self.xOffset)
        }
    }

    private func areHiddenButtonsShowed() -> Bool {
        return self.defaultXOffset == self.getXOffsetToShowHiddenButtons()
    }

    private func hideButtons() {
        self.hiddenButtonWidth = 0
        self.xOffset = CGFloat.zero
        self.defaultXOffset = .zero
    }

    private func getMinDistanceToChangeDefaultXOffset() -> CGFloat {
        return self.hiddenButtonMaxWidth / 2
    }

    private func getXOffsetToShowHiddenButtons() -> CGFloat {
        return (self.hiddenButtonMaxWidth * 2) * -1
    }

    private func showHiddenButtons() {
        self.hiddenButtonWidth = self.hiddenButtonMaxWidth
        self.xOffset = self.getXOffsetToShowHiddenButtons()
        self.defaultXOffset = self.getXOffsetToShowHiddenButtons()
    }
}

PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())



참조


  • https://stackoverflow.com/questions/57700396/adding-a-drag-gesture-in-swiftui-to-a-view-inside-a-scrollview-blocks-the-scroll
  • https://swiftui.i-app-tec.com/ios/draggesture.html

  • 좋은 웹페이지 즐겨찾기