Представіть новий погляд у SwiftUI


11

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

Я вже бачив " Як подати новий вигляд за допомогою аркушів ", але не хочу прикріплювати його до основного виду як модальний аркуш.

І я не хочу використовувати NavigationLink, тому що я не хочу, щоб новий вид і старий вигляд мали відношення до навігації.

Спасибі за вашу допомогу...


Чому ви не хочете прикріплювати його до основного виду як модальний аркуш? Це стандартний метод навіть в UIKit. У вас є якісь особливі причини?
Mojtaba Хоссейні

Я намагаюся пояснити свої думки ... Якщо щось не так, будь ласка, виправте мене.
CH Wing

Додатки мають 3 представлення, 1: Сторінка входу 2: Сторінка входу 3: Сторінка TableDetail, Сторінка TableView та Сторінка TableDetail - це відношення до навігації. Після входу на сторінку TableView сторінка не має жодного стосунку до сторінки входу після входу
CH Wing

Тож вам це потрібно fullscreenправильно?
Mojtaba

так! Я хочу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

Я отримую цю помилку в обгортці властивості середовища: Неможливо перетворити значення типу "Середовище <UIViewController?>" У вказаний тип "UIViewController"
jsbeginnerNodeJS

З нею слід оброблятись за замовчуванням, але спробуйте додати її ?в кінці рядка. @jsbeginnerNodeJS
Mojtaba

Я отримую цю помилку в консолі: `` `Попередження: спроба представити <_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)
                                }}
                            }
                }
                }
        }

-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)
            }
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.