programing

iOS 스위프트UI: 프로그래밍 방식으로 보기 열기 또는 끄기

topblog 2023. 4. 18. 21:41
반응형

iOS 스위프트UI: 프로그래밍 방식으로 보기 열기 또는 끄기

Swift에서 제시한 뷰의 팝 또는 해제프로그래밍 방식으로 만드는 방법에 대한 참조를 찾을 수 없었습니다.UI.

내가 보기에 유일한 방법은 이미 통합된 슬라이드 다우 액션을 모달에 사용하고(이 기능을 비활성화하려면 어떻게 해야 하는가), 뒤로 버튼을 네비게이션 스택에 사용하는 것입니다.

해결책을 아는 사람이 있나요?이게 버그인지 아니면 이대로 있는지 아세요?

이 예에서는 값 속성을 사용하고 있던 베타 5 릴리스 노트에 기재된 새로운 환경 변수를 사용합니다.이후 베타에서 wrapedValue 속성을 사용하도록 변경되었습니다.이 예는 현재 GM 버전에 대해 최신입니다.이 개념은 .sheet 수식자와 함께 표시되는 Modal 뷰를 해제하는 데 사용됩니다.

import SwiftUI

struct DetailView: View {
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var body: some View {
        Button(
            "Here is Detail View. Tap to go back.",
            action: { self.presentationMode.wrappedValue.dismiss() }
        )
    }
}

struct RootView: View {
    var body: some View {
        VStack {
            NavigationLink(destination: DetailView())
            { Text("I am Root. Tap for Detail View.") }
        }
    }
}

struct ContentView: View {
    var body: some View {
        NavigationView {
            RootView()
        }
    }
}

SwiftUI Xcode 베타 5

먼저 뷰를 해제하기 위해 어디서나 사용할 수 있는 해제 메서드가 있는 @Environment를 선언합니다.

import SwiftUI

struct GameView: View {
    
    @Environment(\.presentationMode) var presentation
    
    var body: some View {
        Button("Done") {
            self.presentation.wrappedValue.dismiss()
        }
    }
}

iOS 15 이상

iOS 15부터 새로운 기능을 사용할 수 있습니다.@Environment(\.dismiss):

struct SheetView: View {
    @Environment(\.dismiss) var dismiss

    var body: some View {
        NavigationView {
            Text("Sheet")
                .toolbar {
                    Button("Done") {
                        dismiss()
                    }
                }
        }
    }
}

(더 이상 사용할 필요가 없음)presentationMode.wrappedValue.dismiss().)


유용한 링크:

Navigation View에서 프로그래밍 방식으로 팝업을 수행할 수 있습니다.이건 베타 5입니다.뒤로 버튼은 필요 없습니다.원하는 방식으로 DetailView에서 showSelf 속성을 프로그래밍 방식으로 트리거할 수 있습니다.또한 마스터에 "Push" 텍스트를 표시할 필요가 없습니다.EmptyView()일 수 있습니다.그 결과, 보이지 않는 segue가 작성됩니다.

import SwiftUI

struct ContentView: View {
    var body: some View {
        NavigationView {
            MasterView()
        }
    }
}

struct MasterView: View {
    @State private var showDetail = false

    var body: some View {
        VStack {
            NavigationLink(destination: DetailView(showSelf: $showDetail), isActive: $showDetail) {
                Text("Push")
            }
        }
    }
}

struct DetailView: View {
    @Binding var showSelf: Bool

    var body: some View {
        Button(action: {
            self.showSelf = false
        }) {
            Text("Pop")
        }
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

저는 최근에 오픈 소스 프로젝트인swiftui-navigation-stack( https://github.com/biobeats/swiftui-navigation-stack) 에는,NavigationStackView, Swift용 대체 내비게이션스택UI. Repo의 readme에 설명된 몇 가지 기능을 제공합니다.예를 들어, 프로그래밍 방식으로 보기를 쉽게 푸시하고 팝할 수 있습니다.간단한 예를 들어 그 방법을 설명하겠습니다.

우선 계층 구조를NavigationStackVew:

struct RootView: View {
    var body: some View {
        NavigationStackView {
            View1()
        }
    }
}

NavigationStackView계층은 다음과 같은 유용한 환경 개체에 액세스할 수 있습니다.NavigationStack예를 들어 위의 질문에 따라 프로그래밍 방식으로 보기를 팝업할 수 있습니다.

struct View1: View {
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 1")
                Spacer()

                PushView(destination: View2()) {
                    Text("PUSH TO VIEW 2")
                }
            }
        }
    }
}

struct View2: View {
    @EnvironmentObject var navStack: NavigationStack
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 2")
                Spacer()

                Button(action: {
                    self.navStack.pop()
                }, label: {
                    Text("PROGRAMMATICALLY POP TO VIEW 1")
                })
            }
        }
    }
}

이 예에서는,PushView탭으로 푸시 내비게이션을 트리거합니다.그리고 나서View2환경 오브젝트를 사용하여 프로그래밍 방식으로 복귀합니다.

다음으로 완전한 예를 제시하겠습니다.

import SwiftUI
import NavigationStack

struct RootView: View {
    var body: some View {
        NavigationStackView {
            View1()
        }
    }
}

struct View1: View {
    var body: some View {
        ZStack {
            Color.yellow.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 1")
                Spacer()

                PushView(destination: View2()) {
                    Text("PUSH TO VIEW 2")
                }
            }
        }
    }
}

struct View2: View {
    @EnvironmentObject var navStack: NavigationStack
    var body: some View {
        ZStack {
            Color.green.edgesIgnoringSafeArea(.all)
            VStack {
                Text("VIEW 2")
                Spacer()

                Button(action: {
                    self.navStack.pop()
                }, label: {
                    Text("PROGRAMMATICALLY POP TO VIEW 1")
                })
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        RootView()
    }
}

결과는 다음과 같습니다.

여기에 이미지 설명 입력

또는 버튼에서 프로그래밍 방식으로 수행하지 않으려면 팝업해야 할 때마다 뷰 모델에서 내보낼 수 있습니다.저장될 때마다 값을 변경하는 @Published 에 등록합니다.

struct ContentView: View {
    @ObservedObject var viewModel: ContentViewModel
    @Environment(\.presentationMode) var presentationMode

    init(viewModel: ContentViewModel) {
        self.viewModel = viewModel
    }

    var body: some View {
        Form {
            TextField("Name", text: $viewModel.name)
                .textContentType(.name)
        }
        .onAppear {
            self.viewModel.cancellable = self.viewModel
                .$saved
                .sink(receiveValue: { saved in
                    guard saved else { return }
                    self.presentationMode.wrappedValue.dismiss()
                }
            )
        }
    }
}

class ContentViewModel: ObservableObject {
    @Published var saved = false // This can store any value.
    @Published var name = ""
    var cancellable: AnyCancellable? // You can use a cancellable set if you have multiple observers.

    func onSave() {
        // Do the save.

        // Emit the new value.
        saved = true
    }
}

매우 간단하므로 팔로우 코드를 확인하십시오.

첫 번째 표시

struct StartUpVC: View {
@State var selection: Int? = nil

var body: some View {
    NavigationView{
        NavigationLink(destination: LoginView().hiddenNavigationBarStyle(), tag: 1, selection: $selection) {
            Button(action: {
                print("Signup tapped")
                self.selection = 1
            }) {
                HStack {
                    Spacer()
                    Text("Sign up")
                    Spacer()
                }
            }
        }
    }
}

세컨드 뷰

struct LoginView: View {
@Environment(\.presentationMode) var presentationMode
    
var body: some View {
    NavigationView{
        Button(action: {
           print("Login tapped")
           self.presentationMode.wrappedValue.dismiss()
        }) {
           HStack {
              Image("Back")
              .resizable()
              .frame(width: 20, height: 20)
              .padding(.leading, 20)
           }
        }
      }
   }
}

와 「 」를 .Transition.

여기 커스텀 모달입니다.

struct ModalView<Content>: View where Content: View {

    @Binding var isShowing: Bool
    var content: () -> Content

    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .center) {
                if (!self.isShowing) {
                    self.content()
                }
                if (self.isShowing) {
                    self.content()
                        .disabled(true)
                        .blur(radius: 3)

                    VStack {
                        Text("Modal")
                    }
                    .frame(width: geometry.size.width / 2,
                           height: geometry.size.height / 5)
                    .background(Color.secondary.colorInvert())
                    .foregroundColor(Color.primary)
                    .cornerRadius(20)
                    .transition(.moveAndFade) // associated transition to the modal view
                }
            }
        }
    }

}

재이 the the the the the the 를 재사용했다.Transition.moveAndFade애니메이션 보기 및 전환 튜토리얼

이것은 다음과 같이 정의됩니다.

extension AnyTransition {
    static var moveAndFade: AnyTransition {
        let insertion = AnyTransition.move(edge: .trailing)
            .combined(with: .opacity)
        let removal = AnyTransition.scale()
            .combined(with: .opacity)
        return .asymmetric(insertion: insertion, removal: removal)
    }
}

미리 보기가 아닌 시뮬레이터에서 다음과 같이 테스트할 수 있습니다.

struct ContentView: View {

    @State var isShowingModal: Bool = false

    func toggleModal() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            withAnimation {
                self.isShowingModal = true
            }
            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
                withAnimation {
                    self.isShowingModal = false
                }
            }
        }
    }

    var body: some View {
        ModalView(isShowing: $isShowingModal) {
            NavigationView {
                List(["1", "2", "3", "4", "5"].identified(by: \.self)) { row in
                    Text(row)
                }.navigationBarTitle(Text("A List"), displayMode: .large)
            }.onAppear { self.toggleModal() }
        }
    }

}

은 모달로 되어 .sliding in from the trailing edge은 「」, 「」라고 합니다.zoom and fade out when it is dismissed.

Swift의 핵심 컨셉UI는 데이터 흐름을 감시하는 것입니다.

하다를 요.@State변수 및 변수 값을 변환하여 팝핑 및 해제를 제어합니다.

struct MyView: View {
    @State
    var showsUp = false

    var body: some View {
        Button(action: { self.showsUp.toggle() }) {
            Text("Pop")
        }
        .presentation(
            showsUp ? Modal(
                Button(action: { self.showsUp.toggle() }) {
                    Text("Dismiss")
                }
            ) : nil
        )
    }
}

issue가가가가가가가가가가가가가가가가가가 i i i i i i i i i i를 하려고 하는데 컴파일러에 했습니다.value bindingpresentationMode로 합니다.을 " "로 변경"wrappedValue저를 위해 문제를 해결해주셨어요.value->wrappedValue언어 업데이트입니다.Chuck H의 답변에 대한 코멘트로 이 노트가 더 적절할 것 같은데, 코멘트를 하기에는 충분한 rep 포인트가 없기 때문에, 이 변경과 편집을 제안했지만, 제 편집이 코멘트나 답변으로 더 적절하다고 거절당했습니다.

이렇게 하면 뷰도 해제됩니다.

       let scenes = UIApplication.shared.connectedScenes
                let windowScene = scenes.first as? UIWindowScene
                let window = windowScene?.windows.first
                
                window?.rootViewController?.dismiss(animated: true, completion: {
                    print("dismissed")
                })

언급URL : https://stackoverflow.com/questions/56513568/ios-swiftui-pop-or-dismiss-view-programmatically

반응형