programing

Swift UI 해제 모달

instargram 2023. 8. 5. 09:50
반응형

Swift UI 해제 모달

스위프트 이후UI는 선언적입니다. 없습니다.dismiss방법.에서는 어떻게 다음에 해제/닫기 버튼을 추가할 수 있습니까?DetailView?

struct DetailView: View {
  var body: some View {
  Text("Detail")
  }
}

struct ContentView : View {
  var body: some View {
  PresentationButton(Text("Click to show"), destination: DetailView())
  }
}

@State 속성 래퍼 사용(권장)

struct ContentView: View {
    @State private var showModal = false
    
    var body: some View {
       Button("Show Modal") {
          self.showModal.toggle()
       }.sheet(isPresented: $showModal) {
            ModalView(showModal: self.$showModal)
        }
    }
}

struct ModalView: View {
    @Binding var showModal: Bool
    
    var body: some View {
        Text("Modal view")
        Button("Dismiss") {
            self.showModal.toggle()
        }
    }
}

프레젠테이션 모드 사용

사용할 수 있습니다.presentationMode모달 보기 및 호출의 환경 변수self.presentaionMode.wrappedValue.dismiss()모달을 해제하는 방법:

struct ContentView: View {

  @State private var showModal = false

  // If you are getting the "can only present once" issue, add this here.
  // Fixes the problem, but not sure why; feel free to edit/explain below.
  @SwiftUI.Environment(\.presentationMode) private var presentationMode: Binding<PresentationMode>


  var body: some View {
    Button(action: {
        self.showModal = true
    }) {
        Text("Show modal")
    }.sheet(isPresented: self.$showModal) {
        ModalView()
    }
  }
}


struct ModalView: View {

  @Environment(\.presentationMode) private var presentationMode

  var body: some View {
    Group {
      Text("Modal view")
      Button(action: {
         self.presentationMode.wrappedValue.dismiss()
      }) {
        Text("Dismiss")
      }
    }
  }
}

enter image description here

iOS 15+

대신에presentationMode이제 사용할 수 있습니다.DismissAction.

다음은 설명서의 예입니다.

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

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

Xcode 11 Beta 5에서는 모달을 실행하는 뷰에서 @State를 사용하고 모달 뷰에 바인딩을 추가하여 모달의 가시성을 제어합니다.따라서 @Environment presentationMode 변수에 접근할 필요가 없습니다.

struct MyView : View {
    @State var modalIsPresented = false

    var body: some View {
        Button(action: {self.modalIsPresented = true})  {
            Text("Launch modal view")
        }
        .sheet(isPresented: $modalIsPresented, content: {
            MyModalView(isPresented: self.$modalIsPresented)
        })
    }
}


struct MyModalView : View {
    @Binding var isPresented: Bool
    
    var body: some View {
        Button(action: {self.isPresented = false})  {
            Text("Close modal view")
        }
    }
}

다음은 제시된 보기를 무시하는 방법입니다.

struct DetailView: View {
    @Binding
    var dismissFlag: Bool

    var body: some View {
        Group {
            Text("Detail")
            Button(action: {
                self.dismissFlag.toggle()
            }) {
                Text("Dismiss")
            }
        }

    }
}

struct ContentView : View {
    @State var dismissFlag = false

    var body: some View {
        Button(action: {
            self.dismissFlag.toggle()
        })
        { Text("Show") }
            .presentation(!dismissFlag ? nil :
                Modal(DetailView(dismissFlag: $dismissFlag)) {
                print("dismissed")
            })
    }
}

enter image description here

Xcode 11 베타 7(이것은 Xcode의 빌드 11M392r에 있음)의 경우 약간 다른 것 같습니다.

@Environment(\.presentationMode) var presentation


Button(action: { self.presentation.wrappedValue.dismiss() }) { Text("Dismiss") }

Swift 5.5 및 Swift의 새로운 기능UI 3:

@Environment(\.dismiss) var dismiss

그런 다음 기능 또는 신체 코드의 어딘가에서 간단히 전화하십시오.

self.dismiss()

구현할 수 있습니다.

struct view: View {
    @Environment(\.isPresented) private var isPresented

    private func dismiss() {
        isPresented?.value = false
    }
}

자동으로 팝업 표시(인 경우)Navigation또는 다음과 같은 경우에 기각합니다.Modal


그냥 가져가세요.presentationMode대상 보기의 환경에서 사용할 수 있습니다.dismisswrappedValue여기서:

struct DestinationView: View {
    @Environment(\.presentationMode) private var presentationMode

    var body: some View {
        Button("Dismiss") {
            self.presentationMode.wrappedValue.dismiss()
        }
    }
}


데모(팝/해제)

Pop Dismiss

이제 베타 5에서 이를 수행하는 꽤 깨끗한 방법이 있습니다.

import SwiftUI

struct ModalView : View {
    // In Xcode 11 beta 5, 'isPresented' is deprecated use 'presentationMode' instead
    @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>
    var body: some View {
        Group {
            Text("Modal view")
            Button(action: { self.presentationMode.wrappedValue.dismiss() }) { Text("Dismiss") }
        }
    }
}

struct ContentView : View {
    @State var showModal: Bool = false
    var body: some View {
        Group {
            Button(action: { self.showModal = true }) { Text("Show modal via .sheet modifier") }
                .sheet(isPresented: $showModal, onDismiss: { print("In DetailView onDismiss.") }) { ModalView() }
        }
    }
}

부터PresentationButton사용하기 쉽지만 예측 특성을 훼손하는 상태를 숨깁니다.SwiftUI액세스 가능한 상태로 구현했습니다.Binding.

public struct BindedPresentationButton<Label, Destination>: View where Label: View, Destination: View {
    /// The state of the modal presentation, either `visibile` or `off`.
    private var showModal: Binding<Bool>

    /// A `View` to use as the label of the button.
    public var label: Label

    /// A `View` to present.
    public var destination: Destination

    /// A closure to be invoked when the button is tapped.
    public var onTrigger: (() -> Void)?

    public init(
        showModal: Binding<Bool>,
        label: Label,
        destination: Destination,
        onTrigger: (() -> Void)? = nil
    ) {
        self.showModal = showModal
        self.label = label
        self.destination = destination
        self.onTrigger = onTrigger
    }

    public var body: some View {
        Button(action: toggleModal) {
            label
        }
        .presentation(
            !showModal.value ? nil :
                Modal(
                    destination, onDismiss: {
                        self.toggleModal()
                    }
                )
        )
    }

    private func toggleModal() {
        showModal.value.toggle()
        onTrigger?()
    }
}

사용 방법은 다음과 같습니다.

struct DetailView: View {
    @Binding var showModal: Bool

    var body: some View {
        Group {
            Text("Detail")
            Button(action: {
                self.showModal = false
            }) {
                Text("Dismiss")
            }
        }
    }
}

struct ContentView: View {
    @State var showModal = false

    var body: some View {
        BindedPresentationButton(
            showModal: $showModal,
            label: Text("Show"),
            destination: DetailView(showModal: $showModal)
        ) {
            print("dismissed")
        }
    }
}

Xcode 11.0 베타 7에서는 이제 값이 래핑되어 다음 기능이 작동합니다.

func dismiss() {
    self.presentationMode.wrappedValue.dismiss()
}

Swift의 모달 뷰UI는 나중에 사용하기 시작하기 전까지는 간단한 것 같습니다.List또는Form뷰. 나는 모든 가장자리 케이스를 싸고 모달 뷰의 사용을 동일하게 만드는 작은 라이브러리를 만들었습니다.NavigationView-NavigationLink짝.

도서관은 https://github.com/diniska/modal-view 에서 개방형으로 운영됩니다.Swift Package Manager를 사용하거나 라이브러리에 포함된 단일 파일을 복사하여 프로젝트에 포함할 수 있습니다.

코드 해결 방법은 다음과 같습니다.

struct DetailView: View {
    var dismiss: () -> ()
    var body: some View {
        Text("Detail")
        Button(action: dismiss) {
            Text("Click to dismiss")
        }
    }
}

struct ContentView : View {
    var body: some View {
        ModalPresenter {
            ModalLink(destination: DetailView.init(dismiss:)) {
                Text("Click to show")
            }
        }
    }
}

또한 다음과 같은 자세한 설명과 예제가 포함된 기사가 있습니다.Swift UI에서 모달 뷰를 표시하는 방법

프레젠테이션 모드를 사용하여 해제할 수 있습니다.선언하다

@Environment(\.presentationMode) var presentationMode: Binding<PresentationMode>

그런 다음 필요한 경우 다음과 같이 해제합니다.

self.presentationMode.wrappedValue.dismiss()

프레젠테이션 모드에서 환경 변수를 사용합니다.이 GitHub 링크는 문제를 해결하는 데 도움이 될 것입니다. https://github.com/MannaICT13/Sheet-in-SwiftUI

간단한 솔루션은 다음과 같습니다.

struct ContentView2 : View {

    @Environment (\.presentationMode) var presentationMode

    var body : some View {
        VStack {
            Text("This is ContentView2")
            Button(action: {
                self.presentationMode.wrappedValue.dismiss()
            }, label: {
                Text("Back")    
            })    
        }
    }
}


struct ContentView: View {

    @State var isShowingSheet : Bool = false

    var body: some View {
        Button(action: {
            self.isShowingSheet.toggle()
        }, label: {
            Text("Click Here")
        }).sheet(isPresented: $isShowingSheet, content: {  
            ContentView2()
        })
    }
}

이 작업을 수행하는 한 가지 방법은 모달 프레젠테이션 및 해제에 대한 고유한 수식어를 선언하는 것입니다.

extension View {

  func showModal<T>(_ binding: Binding<Bool>, _ view: @escaping () -> T) -> some View where T: View {

    let windowHeightOffset = (UIApplication.shared.windows.first?.frame.height ?? 600) * -1

    return ZStack {

      self

      view().frame(maxWidth: .infinity, maxHeight: .infinity).edgesIgnoringSafeArea(.all).offset(x: 0, y: binding.wrappedValue ? 0 : windowHeightOffset)

    }

  }
}

그런 다음 뷰를 표시하고 해당 뷰를 해제하는 방법을 알려줄 뷰에 대한 한정자를 사용할 수 있습니다.팝업이나 시트 수식어처럼 말입니다.

struct ContentView: View {

  @State var showModal = false

  var body: some View {

    Text("Show").foregroundColor(.blue).onTapGesture {
      withAnimation(.easeIn(duration: 0.75)) {
        self.showModal = true
      }
    }.showModal($showModal, {

      Text("Dismiss").foregroundColor(.blue).onTapGesture {
        withAnimation(.easeIn(duration: 0.75)) {
          self.showModal = false
        }
      }

    })


  }
}    

프레젠테이션이 위에서 전체 화면으로 표시됩니다. 측면에서 표시하려면 수식어 내부의 전환을 선행 또는 후행으로 변경하십시오.불투명도나 규모와 같은 다른 전환도 가능합니다.

enter image description here

Swift UI 2 코드 샘플(모바일에서도 작동)

(1과 이 되지 , (sample code는 swift 1과 연동이 되지 않습니다.) 할 수 @main으)로 표시)

시트 사용을 위한 전체 앱 샘플:

@main
struct TestAppApp: App {
    var body: some Scene {
        WindowGroup {
            SheetLink(text: "click me!", content: ChildView() )
                .padding(.all, 100)
        }
    }
}

struct ChildView: View {
    var body: some View {
        Text("this is subView!")
    }
}

enter image description here

하위 뷰가 기본 뷰보다 클 경우:

enter image description here

그리고 그 이면의 코드는:

struct SheetLink<Content> : View where Content: View {
    @State var text: String
    @State var displaySheet = false
    @State var content: Content


    var body: some View {
        HStack {
            Button(text, action: { self.displaySheet = true } ).buttonStyle(PlainButtonStyle()).foregroundColor(.blue)
        }
        .sheet(isPresented: $displaySheet) {
            SheetTemplateView(isPresented: self.$displaySheet, content: content)
        }
    }
}

struct SheetTemplateView<Content> : View where Content: View {
    @Binding var isPresented: Bool
    @State var content: Content
    
    var body: some View {
        VStack{
            HStack{
                Button("Back!", action: { isPresented.toggle() } ).buttonStyle(PlainButtonStyle()).foregroundColor(.blue)
                Spacer()
            }
            Spacer()
            content
            Spacer()
        }
        .padding()
    }
}

SheetKit를 사용하여 모든 시트를 제거할 수 있습니다.

SheetKit().dismissAllSheets()

또는 새로운 UISheet 프레젠테이션 컨트롤러 제공

sheetKit.present(with: .bottomSheet){
  Text("Hello world")
}

언급URL : https://stackoverflow.com/questions/56517400/swiftui-dismiss-modal

반응형