Мне удалось настроить Navigationstack, который я использую программно для вставки/удаления представлений. В моем FindOrderView я хочу перенести переменную «ordernumber» в мой LoadingScreen (View) с помощью Binding, но я получаю сообщение об ошибке, говорящее, что мой LoadingScreen не соответствует типу «Equatable». Что я могу делать неправильно, и есть ли другой эффективный способ заставить это работать?
Я новичок в SwiftUi, но искал несколько часов, прежде чем опубликовать это здесь. Благодарен за любую помощь.
NavigationRouter (класс, используемый для управления слоями представлений)
import Foundation
import SwiftUI
enum Route: Hashable {
case ContentView
case View1
}
final class NavigationRouter: ObservableObject {
@Published var navigationPath = NavigationPath()
func pushView(route: Route) {
navigationPath.append(route)
}
func popToRootView() {
navigationPath = .init()
}
func popToSpecificView(k: Int) {
navigationPath.removeLast(k)
}
}
Mainapp (приложение запускается здесь, но сразу же переходит к MainScreenView())
import SwiftUI
@main
struct AvhamtningApp: App {
@StateObject var router = NavigationRouter()
var body: some Scene {
WindowGroup {
NavigationStack(path: $router.navigationPath) {
MainScreenView()
.navigationDestination(for: Route.self) { route in
switch route {
case .ContentView:
MainScreenView()
case .View1:
FindOrderView()
}
}
}.environmentObject(router)
}
}
}
MainScreenView (Просмотр с кнопкой «Получить заказ», которая переносит вас в View1 (FindOrderView))
import SwiftUI
struct MainScreenView: View {
@EnvironmentObject var router: NavigationRouter
var body: some View {
VStack() {
Text("Testing")
.font(.largeTitle)
.fontWeight(.heavy)
.foregroundColor(.yellow)
.padding(.top, 50)
Spacer()
PrimaryButton(text: "Get Order")
.onTapGesture {
router.pushView(route: .View1)
}
Spacer()
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(.white)).ignoresSafeArea(.all)
}
}
struct MainScreenView_Previews: PreviewProvider {
static var previews: some View {
MainScreenView()
}
}
FindOrderView (просмотр с помощью клавиатуры, если ввести 7 цифр, то вы должны перейти к экрану загрузки() с переменной «порядковый номер» в качестве привязки)
import SwiftUI
var list = [["1","2","3"],["4","5","6"],["7","8","9"],["","0","⌫"]]
struct FindOrderView: View {
@State private var ordernumber: String = ""
@EnvironmentObject var router: NavigationRouter
var body: some View {
VStack(spacing: 25) {
Text(ordernumber)
.font(.largeTitle)
.foregroundColor(.black)
.onChange(of: ordernumber) { newValue in
if ordernumber.count >= 7 {
router.navigationPath.append(LoadingScreen(ordernumber: $ordernumber))
}
}
Spacer()
ForEach(list.indices, id: \.self) { listindex in
HStack{
ForEach(list[listindex], id: \.self) { variableindex in
Text(variableindex)
.foregroundColor(.blue)
.font(.system(size: 60))
.onTapGesture(perform: {
if variableindex == "⌫" && !ordernumber.isEmpty {
ordernumber.removeLast()
}
else if ordernumber.count >= 7 {return}
else if variableindex == "⌫" {
()
}
else {
ordernumber += variableindex
}})
.frame(maxWidth: .infinity)
}
}
}
}.background(.white)
}
}
struct FindOrderView_Previews: PreviewProvider {
static var previews: some View {
FindOrderView()
}
}
LoadingScreen (здесь я получаю сообщение об ошибке «Тип« LoadingScreen »не соответствует протоколу« Equatable »»)
import SwiftUI
struct LoadingScreen: Hashable, View {
@EnvironmentObject var router: NavigationRouter
@Binding var ordernumber: String
var body: some View {
ZStack{
Text("Loading...")
.font(Font.custom("Baskerville-Bold", size: 50))
.foregroundColor(.orange)
.padding(.bottom, 200)
ProgressView()
.progressViewStyle(CircularProgressViewStyle(tint: .orange))
.scaleEffect(2)
}.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color(.white)).ignoresSafeArea(.all)
}
}
struct LoadingScreen_Previews: PreviewProvider {
static var previews: some View {
LoadingScreen(ordernumber: .constant("constant"))
}
}
@Jessy Привет, Джесси, спасибо за комментарий. Хорошо! Я только добавил Hashable в представление Loadingscreen, потому что xcode сказал, что он должен соответствовать ему, а затем появилась другая ошибка, говорящая, что он должен соответствовать Equatable. Что бы вы посоветовали мне прочитать, чтобы лучше понять, что я могу делать неправильно? Спасибо за ваш вклад, ценю.
Вас просят сделать LoadingScreen
хешируемым, так как в вашем маршрутизаторе вы добавляете его поверх свойства navigationPath
.
@flanker привет! Да, я тоже так думал, но не смог сделать его хешируемым, кажется, что свойства Environmentobject и Bindingobject вызывают некоторые проблемы, вы знаете, как это решить? Спасибо!
Я не понимаю вашего подхода к логике навигации, и у меня нет времени разбираться со всем кодом, поэтому боюсь, что не могу помочь.
Таким образом, приложение запускается на MainScreenView
, потому что оно установлено как корень NavigationStack.
Ваша проблема с навигацией заключается в том, что вы пытаетесь отправить представление в качестве значения назначения навигации, но вам нужно отправить значение маршрута и включить navigationDestination
, чтобы сгенерировать представление для отправки.
Итак, в вашем перечислении Route
добавьте маршрут для загрузки:
case loading(orderNumber: String)
Затем в своем NavigationLink
отправьте этот новый маршрут:
NavigationLink(value: Route.loadingScreen(orderNumber: orderNumber)
Затем в модификаторе вида navigationDestination
:
.navigationDestination(for: Route.self) { route in
switch route {
case .ContentView:
MainScreenView()
case .View1:
FindOrderView()
case .loading(let orderNumber):
LoadingScreen(orderNumber: orderNumber)
.environmentObject(router)
}
}
Надеюсь это поможет!
Hashable
происходит отEquatable
. Почему вы решили, чтоLoadingScreen
может бытьHashable
?