Перейти к новому представлению с помощью SwiftUI

У меня есть базовое представление с кнопкой, использующей SwiftUI, и я пытаюсь представить новый экран/представление при нажатии кнопки. Как мне это сделать? Должен ли я создать делегата для этого представления, который сообщит приложению SceneDelegate представить новый контроллер представления?

import SwiftUI

struct ContentView : View {
    var body: some View {
        VStack {
            Text("Hello World")
            Button(action: {
                //go to another view
            }) {
                Text("Do Something")
                    .font(.largeTitle)
                    .fontWeight(.ultraLight)
            }
        }
    }
}

Ознакомьтесь с навигационной библиотекой SwiftUI github.com/canopas/UIPilot для удобной навигации.

jimmy0251 24.02.2022 11:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
68
1
96 041
12
Перейти к ответу Данный вопрос помечен как решенный

Ответы 12

Ответ принят как подходящий

Ключ в том, чтобы использовать NavigationView и NavigationLink:

import SwiftUI

struct ContentView : View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
                NavigationLink(destination: DetailView()) {
                    Text("Do Something")
                }
            }
        }
    }
}

NB На данный момент этот подход не работает на Apple Watch, поскольку «NavigationView» недоступен в watchOS. Вы можете использовать только NavigationLink, как описано здесь.

sgiraz 01.12.2019 20:54

Это работает, но тесно связывает эти представления. Есть ли лучший подход, при котором одно представление не знает о другом?

Zorayr 06.05.2020 04:42

Есть ли способ сделать это с помощью Button вместо уродливой NavigationLink?

Andrew K 28.11.2020 00:49

Необходимо создать DetailView, например LandmarkDetail(). и вызовите NavigationButton с пунктом назначения LandmarkDetail(). Теперь детальный вид был открыт.

Для передачи значений в подробные средства экрана. отправив код, как показано ниже.

struct LandmarkList: View {
    var body: some View {
        NavigationView {
            List(landmarkData) { landmark in
                NavigationButton(destination: LandmarkDetail()) {
                    LandmarkRow(landmark: landmark)
                }
            }
            .navigationBarTitle(Text("Landmarks"))
        }
    }
}

Вот еще один способ представить представление БЕЗ использования NavigationView. Это как UIKit UIModalPresentationStyle.currentContext.

struct PresenterButtonView: View {
var body: some View {
    PresentationButton(Text("Tap to present"),
                       destination: Text("Hello world"))
}}

Хм. Откуда PresentationButton?

Chris Prince 29.06.2021 05:46

На OP здесь отвечали несколько раз, но я просто хотел также продемонстрировать интересные аспекты SwiftUI, показав, что если у вас есть представление A с данными, которые также будет использовать представление B, вы можете передавать данные, создав @State в представлении A и объявление той же переменной с объявлением @Binding в представлении B

struct ViewA : View {
    @State var myItems: [Items]
    var body: some View {
        NavigationView {
            VStack {
                NavigationButton(destination: ViewB(items: $myItems)) {
                    Text("Go To ViewB")
                }
            }
        }
    }
}
struct ViewB : View {
    @Binding var myItems: [Items]
    var body: some View {
        NavigationView {
            List{
                ForEach(myItems.identified(by: \.self)) {
                    Text($0.itemName)
                }
            }.navigationBarTitle(Text("My Items"))
        }
    }
}

Вы больше не можете использовать NavigationButton. Вместо этого вы должны использовать NavigationLink.

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: DetailView()) {
                Text("Push new screen")
            }
        }
    }
}

Теперь мы можем использовать НавигацияСсылка


Файл А:

struct ContentView: View {
var body: some View {
    NavigationView {
        VStack {
            Text("Hello World")
            NavigationLink(destination: secondView()) {
                Text("Hit Me!")
                    .fontWeight(.semibold)
                    .font(.title)
                    .padding()
                    .foregroundColor(.white)
                    .background(LinearGradient(gradient: Gradient(colors: [Color(.white),Color(.blue)]), startPoint: .leading, endPoint: .trailing))
                    .cornerRadius(40)
        }
      }
    }
  }
}

Файл Б:

struct secondView: View {
var body: some View {
    VStack {
    VStack(alignment: .leading) {
        Text("Turtle Rock")
            .font(.title)
        HStack(alignment: .top) {
            Text("Joshua Tree National Park")
                .font(.subheadline)
            Spacer()
            Text("California")
                .font(.subheadline)
        }
    }
    .padding()
        Spacer()

    }
  }
}                                                                                                  

Это не должно было быть здесь лучшим ответом, а скорее альтернативным методом, если вам не нужна панель навигации. См. ответ Джейка ниже, чтобы узнать, как это сделать с помощью NavigationView и NavigationLink. Надеюсь, это все еще полезно или укажет вам правильное направление.

Если вы просто пытаетесь заставить NavigationLink работать с Binding, вы можете использовать тот же NavigationLink init, который я сделал с параметром привязки isActive.

Anyway, back to the answer…


Я сделал модификатор представления для этого. Это также означает, что нет панели навигации. Вы можете назвать это так:

.navigate(to: MainPageView(), when: $willMoveToNextScreen)

Его можно прикрепить к чему угодно, поэтому я обычно прикрепляю его к концу тела, например:

@State private var willMoveToNextScreen = false

var body: some View {
    VStack {
        /* ... */
    }
    .navigate(to: MainPageView(), when: $willMoveToNextScreen)
}

Код (не забудьте import SwiftUI):

extension View {
    /// Navigate to a new view.
    /// - Parameters:
    ///   - view: View to navigate to.
    ///   - binding: Only navigates when this condition is `true`.
    func navigate<NewView: View>(to view: NewView, when binding: Binding<Bool>) -> some View {
        NavigationView {
            ZStack {
                self
                    .navigationBarTitle("")
                    .navigationBarHidden(true)

                NavigationLink(
                    destination: view
                        .navigationBarTitle("")
                        .navigationBarHidden(true),
                    isActive: binding
                ) {
                    EmptyView()
                }
            }
        }
        .navigationViewStyle(.stack)
    }
}

аккуратный подход, хотя он, казалось, нарушил мои ранее существовавшие представления с уже примененным стилем.

ty1 22.03.2020 09:05

очень лаконично, аккуратно. Лучший

Ktt 14.04.2020 12:08

Хорошо сделано. Еще один момент, есть ли шанс изменить анимацию навигации? По умолчанию всегда было слева направо.

sakiM 30.07.2020 09:25

@sakiM Как бы вы его оживили? Это значение по умолчанию и стандарт, поэтому я просто оставил все как есть. Если вы хотите, чтобы это исходило снизу, я бы предложил вместо этого .sheet. Не путайте пользователей неожиданным поведением

George 30.07.2020 11:04

К сожалению, в Xcode 12.2 это работает, но в середине исходного экрана появляется маленький серый прямоугольник. Так что это уже нежизнеспособно.

Plasma 22.11.2020 02:00

@Plasma Это кажется очень странным. Можете ли вы загрузить на imgur и ответить со ссылкой, чтобы я мог видеть?

George 22.11.2020 02:35

@George_E вот, пожалуйста .. маленький серый круглый прямоугольник появляется сразу после добавления .navigate(to: MainPageView(), when: $willMoveToNextScreen) внизу моего представления, если я закомментирую эту строку, круглый прямоугольник исчезнет... .. imgur.com/r4lblhn

Plasma 22.11.2020 13:06

@Plasma Попробуйте использовать это в пустом проекте. Мне кажется, это вообще никак не связано со мной. Это может быть проблема с предварительным просмотром (попробуйте симулятор), но если нет, то, вероятно, что-то в вашем коде вы случайно пропустили. Для меня это почти похоже на .redacted(reason: .placeholder), но я не уверен

George 22.11.2020 13:34

@George_E после тщательного тестирования кажется, что проблема возникает только в том случае, если целью является tvOS, отлично работает на IOS. Но при установке на tvOS серый прямоугольник виден в предварительном просмотре, симуляторе и на реальном устройстве.

Plasma 22.11.2020 19:39

Я получаю Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want с каждым .navigate()

Rahul Gaur 25.03.2021 12:23

Это потрясающе. спасибо, что поделились этим.

drago 08.05.2021 15:58

Привет, @George, у меня та же проблема, что и у Раухала Гаура при использовании iOS 15. С iOS 14 у меня нет никаких ошибок.

Tiago Mendes 18.11.2021 18:23

@RahulGaur, вы нашли способ исправить ошибки ограничений?

Tiago Mendes 18.11.2021 18:24

@TiagoMendes Добавление .navigationViewStyle(.stack) к NavigationView, вероятно, исправит это.

George 18.11.2021 18:27

@ Джордж спасибо ? это решило проблему

Tiago Mendes 18.11.2021 18:34

Я думаю, что ответ Джейка - это основной путь к NextView.

И я думаю, что способ, описанный ниже, — это способ простой, формальный и динамичный попробовать, если вам действительно нужно нажать КНОПКУ. Согласно Видео Пола Хадсона, с 10:00 до 12:00.

(должен идти от 12:00 до 15:00, если вы хотите перейти к разные взгляды, нажимая разные кнопки.) (должен идти от 15:00 до 16:00, если вы хотите перейти к второму виду и вернуться назад автоматически.) И многое другое.

А вот и пример кода.

import SwiftUI

struct ContentView: View {

    @State var areYouGoingToSecondView: Bool // Step 2

    var body: some View {
        NavigationView{ // Step 1

            VStack {

                // Step 3
                NavigationLink(destination: YourSecondView(), isActive: $areYouGoingToSecondView) { EmptyView() }


                Text("Hello World")

                Button(action: {
                    self.areYouGoingToSecondView = true // Step 4

                }) {
                    Text("Do Something (Go To Second View)")
                    .font(.largeTitle)
                    .fontWeight(.ultraLight)
                }
            }
        }
    }
}

если не хочет показать навигацияВид, вы можете скрыть его в пункте назначения.

struct ContentViewA : View {
    var body: some View {
        NavigationView {
            VStack {
                Text("Hello World")
                NavigationLink(destination: ContentViewB()) {
                    Text("Go To Next Step")
                }
            }
        }
    }
}



struct ContentViewB : View {
        var body: some View {
            NavigationView {
                VStack {
                    Text("Hello World B")

                }.navigationBarTitle("")
                .navigationBarHidden(true)
            }
        }
    }

или если вы хотите скрыть его в зависимости от условий, вы можете использовать @State для изменения видимости.

Примечание. .navigationBarTitle("") скрывает текст, но неуклюже оставляет пробелы в пустом представлении. Таким образом, можно просто использовать модификатор .navigationBarHidden(true), а затем реализовать пользовательскую кнопку «Назад» или альтернативную навигацию.

Sami Fouad 20.01.2021 11:22

Проблема с использованием навигационного представления и просто сокрытием вещей заключается в том, что 1) вы все еще находитесь в модели push/pop, и если вы никогда не собираетесь возвращаться назад (pop), то это представление сидит там, потребляя память и циклы (в зависимости от по своей структуре и сложности) и никогда не утилизируется. Может быть, это не проблема в большой схеме, но мне кажется, что это немного жирно.

ChrisH 27.01.2021 22:29

Мы можем использовать текст внутри навигации и сделать его похожим на кнопку http://g.recordit.co/CkIkjvikfu.gif

struct HomeContent: View {
    var body: some View {
        NavigationView{
            VStack {
                NavigationLink(
                destination: LoginContentView()) {
                    
                        
                           
                    Text("Login")
                        .font(.title)
                        .foregroundColor(Color.white)
                        .multilineTextAlignment(.center)
                        .frame(width: 300.0, height: 50.0)
                        .background(Color(UIColor.appLightBlue))
                   
                }
                
            }
        }
    }
}

Я думаю, вы упустили суть вопроса. 1) у входа не должно быть кнопки «Назад», 2) все, что осталось под формой входа, все еще там, не удалено, не утилизировано, и 3) что происходит, когда вы нажимаете вход? Конечно, вы захотите перейти на другой экран, возможно, на главный домашний экран приложения, который должен стать новым корнем, а не где-то в середине стека навигации.

ChrisH 27.01.2021 22:33

Пожалуйста, прочитайте вопрос еще раз, вопрос заключался в том, чтобы открыть новый экран, а мой код открывает новый экран.

Varun Naharia 29.01.2021 08:21

Я думаю, что это самый простой и понятный способ. Используйте полноэкранный обложка после инструмента пользовательского интерфейса.

Button(action: {
         //code
         }){
           Text("Send")
         }.fullScreenCover(isPresented: self.$model.goToOtherView, content: {
                    OtherView()
                })

Проблема в том, что он не устанавливает цвет фона для fullScreenCover.

RussellHarrower 12.10.2020 12:37

Интересно, но я также вижу, что это функция только для iOS 14.0 в XCode.

truedat101 03.12.2020 09:29

Чтобы программно перейти к ссылке без отображения визуального элемента, наложите на одно из представлений скрытую NavigationLink.

В этом примере пользовательский интерфейс будет перемещаться, когда какой-то код устанавливает для shouldNavigate значение true:

struct ProgramaticSample {
    @State var shouldNavigate = false
    
    var body: some View {
        Text("Hello navigation")
            .overlay(NavigationLink(
                destination: DestinationScreen(),
                isActive: $shouldNavigate) {}
                .hidden())
    }
}

Другие вопросы по теме