从网络请求更新 EnvironmentObject 后,NavigationLink 在嵌套的 ScrollView 中不起作用
Posted
技术标签:
【中文标题】从网络请求更新 EnvironmentObject 后,NavigationLink 在嵌套的 ScrollView 中不起作用【英文标题】:NavigationLink doesn't work in nested ScrollView after EnvironmentObject update from network request 【发布时间】:2021-11-26 06:09:30 【问题描述】:我有两个用于 navigationView、Dashboard 和 Userscreen 的选项卡。
Userscreen用于通过网络请求获取用户信息,dashboard是根据用户信息通过网络请求显示信息,这里用户信息就是环境对象。
更新用户信息后,我可以查看仪表板属性,但单击导航链接不起作用。 经过一番测试,我发现 ScrollView -> ScrollView(.horizontal) -> NavigationLink 下的导航链接(根据用户信息显示)不起作用,但 VStack -> ScrollView( 下的导航链接(根据用户信息显示) .horizontal) -> NavigationLink 表现良好。
我想知道我是否在实现中遗漏了什么,或者我想问一下它是否是 XCode 的现有错误?
编辑:更新代码
再次编辑:请参考下面@workingdog的解决方案,整个问题只是由一个简单的愚蠢错误引起的,即没有声明正确的状态/环境对象。
import SwiftUI
import Kingfisher
import Alamofire
struct ExampleView: View
@StateObject var userInfoManager = UserInfoManagerExample()
var body: some View
NavigationView
TabView ()
DashboardScreenExample()
.environmentObject(userInfoManager)
.tabItem
Text("Dashboard")
LoginScreenExample()
.environmentObject(userInfoManager)
.tabItem
Text("UpdateInfo")
.navigationBarTitleDisplayMode(.inline)
.navigationViewStyle(StackNavigationViewStyle())
struct DashboardScreenExample: View
@EnvironmentObject var userInfoManager : UserInfoManagerExample
@State var please : Bool = false
init()
Theme.navigationBarColors(background: UIColor(viewProperties.themered), titleColor: .white)
var viewProperties = ViewProperties()
var body: some View
if(userInfoManager.shouldShowDashboard)
ScrollView//Switch this ScrollView to VStack make Navigation Link work again
//I had other screens too, but screen below is the one causing problem
DashboardContentExample()
else
ProgressView().onAppearuserInfoManager.shouldShowDashboard = true
struct DashboardContentExample: View
@EnvironmentObject var userInfoManager : UserInfoManagerExample
@ObservedObject var dashboardList = DashboardConfigRequestExample()
func loadRequest()
dashboardList.loadData(passedLanguage: userInfoManager.preferenceLangauge)
//View start from here
var body: some View
if(dashboardList.dashboardConfig.count == 0)
ProgressView()
.onAppear
loadRequest()
else
ScrollView(.horizontal)
LazyHStack
//Here is the NavigationLink not working
NavigationLink(destination: EmptyView())
Text("Hello")
struct LoginScreenExample: View
let usernameLoginRequest = UsernameLoginRequestExample()
@EnvironmentObject var userInfoManager : UserInfoManagerExample
@State var loginClicked : Bool = false
var body: some View
VStack(alignment: .leading)
if(userInfoManager.isLogin)
Text("You have logged in.")
.onAppear
loginClicked = false
else
ZStack
VStack
Spacer()
//the username and password had to be entered
Button(action:clickLogin(forUsername: "iamusername", andPassword: "iampassword"))
Text("Sign In")
Spacer()
if(loginClicked)
ProgressView()
func clickLogin(forUsername: String, andPassword: String)
loginClicked.toggle()
usernameLoginRequest.loadData(forUsername: forUsername, andPassword: andPassword, andUserInfo: userInfoManager)
class UserInfoManagerExample : ObservableObject
@Published var isLogin: Bool = false
@Published var username: String = ""
@Published var password: String = ""
@Published var preferenceLangauge: String = "en"
@Published var shouldShowDashboard = true
init()
func updateCredential(forUsername: String, andPassword: String)
username = forUsername
password = andPassword
struct UsernameLoginRequestExample
func loadData(forUsername: String, andPassword: String, andUserInfo: UserInfoManagerExample)
let request_url = "This is the request url"
let request_parameters = getUsernameLoginParameter(withUsername: forUsername, andPassword: andPassword)
AF
.request(request_url, method: .post, parameters: request_parameters, encoding: JSONEncoding.default ).responseJSON
responses
in
debugPrint(responses)
switch responses.result
case .success:
do
andUserInfo.shouldShowDashboard = false
andUserInfo.updateCredential(forUsername: forUsername, andPassword: andPassword)
andUserInfo.isLogin = true
case let .failure(error):
print(error)
func getUsernameLoginParameter(withUsername : String, andPassword : String) -> [String : String]
var parameters : [String : String] = [String : String]()
parameters.updateValue(withUsername, forKey: "username")
parameters.updateValue(andPassword, forKey: "password")
var device_id : String
if(UIDevice.current.identifierForVendor != nil)
device_id = UIDevice.current.identifierForVendor!.uuidString
else
device_id = ""
parameters.updateValue(device_id, forKey:"device_id")
return parameters
class DashboardConfigRequestExample : ObservableObject
@Published var dashboardConfig = [DashboardConfigExample]()
func loadData(passedLanguage : String)
let request_url = "This is request url"
let request_parameters = getDashboardConfigParameter(passedLanguage: passedLanguage)
AF
.request(request_url, method:.post, parameters: request_parameters)
.responseJSON
responses in
switch responses.result
case .success:
guard
let data = responses.data
else return
do
let configResponse = try JSONDecoder().decode(DashboardConfigDataExample.self, from: data)
self.dashboardConfig = configResponse.list ?? []
catch
print(error)
case let .failure(error):
print(error)
func getDashboardConfigParameter(passedLanguage: String) -> [String:String]
var parameters : [String:String] = [String:String]()
parameters.updateValue(passedLanguage, forKey: "language")
return parameters
struct DashboardConfigDataExample : Decodable
public var status: String?
public var list: [DashboardConfigExample]?
struct DashboardConfigExample: Encodable & Codable
let background_image: String?
let background_color: String?
【问题讨论】:
您的代码在我的测试中似乎对我有用。单击NavigationLinks
可以工作。在 macos 12.1-beta 上,使用 xcode 13.2-beta,针对 ios 15 和 macCatalyst 12。
感谢您的回复,如果 @Published var
在没有网络请求的情况下更新,我的代码可以正常工作。代码中有两个cmet会从我的后端执行异步网络请求,依次更新环境对象,涉及NavigationLinks
的屏幕需要再次更新,然后NavigationLinks
在请求后将不起作用。但是用VStack
替换ScrollView
以某种方式使NavigationLinks
起作用。
因此,您向我们展示的代码并不是给您带来任何问题的代码。你能告诉我们可以复制你的问题的代码吗?
我改了代码,但是去掉了网络请求参数和url,谢谢。
【参考方案1】:
尝试替换
@ObservedObject var infoRequest = InfoRequest()
在Dashboard
中
@StateObject var infoRequest = InfoRequest()
EDIT1:根据新代码。
尝试移动@ObservedObject var dashboardList = DashboardConfigRequestExample()
的DashboardContentExample
进入ExampleView
为@StateObject
。类似于以下示例代码:
struct ExampleView: View
@StateObject var userInfoManager = UserInfoManagerExample()
@StateObject var dashboardList = DashboardConfigRequestExample() // <-- here
var body: some View
NavigationView
TabView ()
DashboardScreenExample().tabItem Text("Dashboard")
LoginScreenExample().tabItem Text("UpdateInfo")
.navigationBarTitleDisplayMode(.inline)
.environmentObject(userInfoManager) // <-- here
.environmentObject(dashboardList) // <-- here
.navigationViewStyle(StackNavigationViewStyle())
struct DashboardContentExample: View
@EnvironmentObject var userInfoManager : UserInfoManagerExample
@EnvironmentObject var dashboardList: DashboardConfigRequestExample // <-- here
func loadRequest()
dashboardList.loadData(passedLanguage: userInfoManager.preferenceLangauge)
//View start from here
var body: some View
if(dashboardList.dashboardConfig.count == 0)
ProgressView()
.onAppear
loadRequest()
else
ScrollView(.horizontal)
LazyHStack
//Here is the NavigationLink not working
NavigationLink(destination: Text("Hello destination")) // <-- here for testing
Text("Hello")
【讨论】:
我改了,导航链接好像还是不行。顺便说一句,我已经将代码编辑为真正引起我问题的代码,感谢您帮助@workingdog! 根据您的新代码更新了我的答案。 抱歉@workingdog 回复晚了……即使我根据更新后的答案添加了新的@stateobject
和@environmentobject
,导航链接也无法正常工作,但无论如何感谢您提供帮助!但是navigation links
有一个奇怪的行为是,它们在点击时没有响应,但在切换标签后,之前链接的屏幕会立即弹出。
原来是我把环境对象放到了错误的屏幕上,非常感谢!以上是关于从网络请求更新 EnvironmentObject 后,NavigationLink 在嵌套的 ScrollView 中不起作用的主要内容,如果未能解决你的问题,请参考以下文章
Swiftui @EnvironmentObject 在视图中更新
Swift UI - EnvironmentObject 更改不会更新 UI
如何使用@EnvironmentObject 在 SwiftUI 中自动填充和更新列表?
在 SwiftUI 中通过摇动手势(使用 UIKit)设置 EnvironmentObject 不会更新视图