Представьте новый взгляд в SwiftUI

11

Я хочу нажать на кнопку, а затем представить новый вид, как present modallyв UIKit введите описание изображения здесь

Я уже видел « Как представить новый вид с использованием листов », но я не хочу прикреплять его к основному виду как модальный лист.

И я не хочу использовать NavigationLink, потому что я не хочу, чтобы новый вид и старый вид имели отношения навигации.

Спасибо за вашу помощь...

CH Wing
источник
Почему вы не хотите прикрепить его к основному виду в виде модального листа? Это стандартный метод даже в UIKit. У тебя есть особая причина?
Мойтаба Хоссейни
Я пытаюсь объяснить свои мысли ... Если что-то не так, пожалуйста, поправьте меня.
Крыла
Приложения имеют 3 вида: 1: страница входа 2: страница TableView 3: страница TableDetail, страница TableView и страница TableDetail - это отношение навигации. После того, как вход в систему будет представлен на странице TableView, страница TableView не имеет никакого отношения к странице входа в систему после входа в систему
CH Wing
Значит, нужно, чтобы это было fullscreenправильно?
Мойтаба Хоссейни
YS! я хочуfullscreen
CH Wing

Ответы:

12

Показать модал (стиль iOS 13)

Нужно просто простое sheetс возможностью отмахнуться от себя:

struct ModalView: View {
    @Binding var presentedAsModal: Bool
    var body: some View {
        Button("dismiss") { self.presentedAsModal = false }
    }
}

И представить это как:

struct ContentView: View {
    @State var presentingModal = false

    var body: some View {
        Button("Present") { self.presentingModal = true }
        .sheet(isPresented: $presentingModal) { ModalView(presentedAsModal: self.$presentingModal) }
    }
}

Обратите внимание, что я передал presentingModalмодал, чтобы вы могли исключить его из самого модала, но вы можете избавиться от него.


Чтобы сделать его действительно настоящим fullscreen(не только визуально)

Вам необходимо получить доступ к ViewController. Так что вам нужны вспомогательные контейнеры и окружение:

struct ViewControllerHolder {
    weak var value: UIViewController?
}

struct ViewControllerKey: EnvironmentKey {
    static var defaultValue: ViewControllerHolder {
        return ViewControllerHolder(value: UIApplication.shared.windows.first?.rootViewController)

    }
}

extension EnvironmentValues {
    var viewController: UIViewController? {
        get { return self[ViewControllerKey.self].value }
        set { self[ViewControllerKey.self].value = newValue }
    }
}

Затем вы должны использовать это расширение:

extension UIViewController {
    func present<Content: View>(style: UIModalPresentationStyle = .automatic, @ViewBuilder builder: () -> Content) {
        let toPresent = UIHostingController(rootView: AnyView(EmptyView()))
        toPresent.modalPresentationStyle = style
        toPresent.rootView = AnyView(
            builder()
                .environment(\.viewController, toPresent)
        )
        self.present(toPresent, animated: true, completion: nil)
    }
}

в заключение

Вы можете сделать это fullscreenкак:

struct ContentView: View {
    @Environment(\.viewController) private var viewControllerHolder: UIViewController?

    var body: some View {
        Button("Login") {
            self.viewControllerHolder?.present(style: .fullScreen) {
                Text("Main") // Or any other view you like
            }
        }
    }
}
Мойтаба Хоссейни
источник
Великий! спасибо за ваше подробное решение
CH Wing
Я получаю эту ошибку в оболочке свойства среды: не удается преобразовать значение типа «Environment <UIViewController?>» В указанный тип «UIViewController»
jsbeginnerNodeJS
Это должно быть обработано по умолчанию, но попробуйте добавить ?в конце строки там. @jsbeginnerNodeJS
Хоссейни
Я получаю эту ошибку в консоли: `` `Предупреждение: попытка представить <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2641d30> на <_TtGC7SwiftUI19UIHostingControllerVS_7AnyView_: 0x7fafd2611bd0> чей вид не в иерархии окна` ``!
jsbeginnerNodeJS
как вы это отклоняете?
gabrielapittari
0

Вот один простой способ - форвардные взгляды. Это очень прямо вперед.

        struct ChildView: View{
           private  let colors: [Color] = [.red, .yellow,.green,.white]
           @Binding var index : Int
           var body: some View {
           let next = (self.index+1)  % MyContainer.totalChildren
             return   ZStack{
                    colors[self.index  % colors.count]
                     Button("myNextView \(next)   ", action: {
                    withAnimation{
                        self.index = next
                    }
                    }
                )}.transition(.asymmetric(insertion: .move(edge: .trailing)  , removal:  .move(edge: .leading)  ))
            }
        }

        struct MyContainer: View {
            static var totalChildren = 10
            @State private var value: Int = 0
            var body: some View {
                    HStack{
                        ForEach(0..<(Self.totalChildren) ) { index in
                            Group{
                            if    index == self.value {
                                ChildView(index:  self.$value)
                                }}
                            }
                }
                }
        }
E.Coms
источник
-1

Отказ от ответственности: ниже не очень похоже на «нативный модал», ни ведите себя, ни выглядите, но если кому-то понадобится настраиваемый переход одного вида поверх другого, активирующий только верхний, следующий подход может быть полезен.

Итак, если вы ожидаете что-то вроде следующего

пользовательский мод SwiftUI

Вот простой код для демонстрационного подхода (параметры анимации и перехода можно изменить по желанию)

struct ModalView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = false
                }
            }) {
                Text("Hide modal")
            }
            Text("Modal View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.green)
    }
}

struct MainView : View {
    @Binding var activeModal: Bool
    var body : some View {
        VStack {
            Button(action: {
                withAnimation(.easeInOut(duration: 0.3)) {
                    self.activeModal = true
                }
            }) {
                Text("Show modal")
            }
            Text("Main View")
        }
        .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
        .background(Color.yellow)
    }
}

struct ModalContainer: View {
    @State var showingModal = false
    var body: some View {
        ZStack {
            MainView(activeModal: $showingModal)
                .allowsHitTesting(!showingModal)
            if showingModal {
                ModalView(activeModal: $showingModal)
                    .transition(.move(edge: .bottom))
                    .zIndex(1)
            }
        }
    }
}
Asperi
источник