使用 @State 变量不适用于从子视图更改 Body 中的视图状态
Posted
技术标签:
【中文标题】使用 @State 变量不适用于从子视图更改 Body 中的视图状态【英文标题】:Using @State variable does not work for changing view state in Body from child view 【发布时间】:2021-06-20 12:44:38 【问题描述】:假设在我的 ios SwiftUI 应用中有一个简单的 ContentView,里面有两个视图。
对 ContentView 的引用可用于代码的其他部分。
从那里,用户想要确定显示两个视图中的哪一个,即一个、不显示或两者都显示。
那个代码有点像
contentViewReference.setView1Visible(view1Visible:true) //or false
这是内容视图
struct ViewsState
var view1Visible:Bool
var view2Visible:Bool
init(view1Visible:Bool,view2Visible:Bool)
self.view1Visible=view1Visible
self.view2Visible=view2Visible
struct ContentView: View
@State private var viewsState:ViewsState=ViewsState(view1Visible:true,view2Visible:false)
public func setView1Visible(view1Visible:Bool)
viewsState.view1Visible=view1Visible
public func setView2Visible(view2Visible:Bool)
viewsState.view2Visible=view2Visible
var body: some View
if (viewsState.view1Visible) View1
if (viewsState.view1Visible) View2
但是视图的可见性永远不会改变,为什么?
我认为我不需要绑定,因为状态“真相”在 ContentView 内部,但它是通过公共函数分配的。
没有父视图,切换代码确实在 View1 的菜单中。
但是打电话的时候
setView1Visible(view1Visible:false)
比如没有效果,View1 不会被隐藏。
这只是一段代码。 Real ContentView 稍微复杂一些,但问题没有改变。
【问题讨论】:
嗨 P5Music,视图的可见性取决于两个单独的条件,还是可见性取决于一个条件?我想知道是一个可见还是两者都可见或不可见?其次,什么决定了知名度?是用户点击还是其他条件? @MacUserT 在真正的应用程序中,我将其用作一种导航系统,所以是的,理想情况下,当 View1 被隐藏时,View2 就会变得可见。我知道它是实验性的,但我需要知道它是如何工作的,它没有理由不起作用,即使作为练习也是如此。@State
应为大写
如果两者都是false
,则很可能需要else
中的某些视图。
另外,您不能从另一个View
、class
、struct
访问View
中的方法,理想情况下,用户将直接访问您的ViewState
而不是ContentView
跨度>
【参考方案1】:
class ViewsState: ObservableObject
@Published var view1Visible:Bool
@Published var view2Visible:Bool
init(view1Visible:Bool,view2Visible:Bool)
self.view1Visible=view1Visible
self.view2Visible=view2Visible
public func setView1Visible(view1Visible:Bool)
self.view1Visible = view1Visible
view2Visible = !view1Visible
public func setView2Visible(view2Visible:Bool)
self.view2Visible = view2Visible
view1Visible = !view2Visible
struct ViewStateView: View
@StateObject private var viewsState: ViewsState = ViewsState(view1Visible:true,view2Visible:false)
var body: some View
VStack
if (viewsState.view1Visible) Text("View1")
if (viewsState.view2Visible) Text("View2")
SomeOtherView().environmentObject(viewsState)
struct SomeOtherView: View
@EnvironmentObject var viewsState: ViewsState
var body: some View
VStack
Text("SomeOtherView")
Button("change state view 1", action:
viewsState.setView1Visible(view1Visible:false)
)
Button("change state view 2", action:
viewsState.setView2Visible(view2Visible:false)
)
struct ViewStateView_Previews: PreviewProvider
static var previews: some View
ViewStateView()
【讨论】:
我得到“没有找到 ViewsState 类型的 ObservableObject。ViewsState 的 View.environmentObject(_:) 作为此视图的祖先可能会丢失”无论我使用什么方法来“创建”和注入该对象在 Views 中,从 ContentView 等开始。在 Views 层次结构中拥有一个“实时”的 Observable 和 State 对象的解决方案是什么? 你必须在启动视图时添加这个 .environmentObject() 看看 SomeOtherView 在 body 中初始化 我有一些视图,一个叫做 mainView,但它在 ContentView 中,但它需要一个自身的 StateObject,在运行时它说每次都会创建一个新实例,但是如果我使用 environmentObject 代替,它表示祖先中没有可观察的对象。 表示初始化时需要 environmentObject 修饰符的视图。你必须把它传下去。在某些情况下,例如表格不会自动传递。在 SO 中多次询问过同样的错误 我确保我的代码与您的代码相似,只是在 mainView 的主体中,它有一个返回 EmptyView 的 func 调用,用于设置一些 viewsState 成员,以便在下面立即使用它们。该函数只是将一个子视图设置为可见,另一个隐藏。【参考方案2】:@P5music,没有足够的代码来复制您的问题并正确调查。 另外我不知道你是怎么得到的:
contentViewReference.setView1Visible(view1Visible:true)
以下是对您的代码的一些观察。
@State private var viewsState:ViewsState(view1Visible:true,view2Visible:false)
应该是
@State var viewsState = ViewsState(view1Visible:true,view2Visible:false)
你也可能想要:
var body: some View
if (viewsState.view1Visible) View1
if (viewsState.view2Visible) View2 // <--- here
另外,“...确定显示两个视图中的哪一个”,这意味着每次设置 “view1Visible”设置为某个值,同时还需要将“view2Visible”设置为相反的值。
【讨论】:
别忘了大写@State
是的,谢谢,我刚刚更新了答案/评论。
@workingdog 现在哪个视图可见或不可见并不重要,这应该可以工作。如何解决?【参考方案3】:
假设您的“contentViewReference.setView1Visible(view1Visible:true)”有效,以下 测试代码似乎可以工作:
import SwiftUI
@main
struct TestApp: App
var body: some Scene
WindowGroup
ContentView()
struct ViewsState
var view1Visible:Bool
var view2Visible:Bool
init(view1Visible:Bool, view2Visible:Bool)
self.view1Visible = view1Visible
self.view2Visible = view2Visible
struct ContentView: View
@State var viewsState = ViewsState(view1Visible:true, view2Visible:false)
public func setView1Visible(view1Visible:Bool)
viewsState.view1Visible = view1Visible
viewsState.view2Visible = !view1Visible
public func setView2Visible(view2Visible:Bool)
viewsState.view2Visible = view2Visible
viewsState.view1Visible = !view2Visible
var body: some View
VStack
Button("change view")
if viewsState.view1Visible
setView1Visible(view1Visible: false)
else
setView1Visible(view1Visible: true)
if (viewsState.view1Visible) View1()
if (viewsState.view2Visible) View2()
struct View1: View
var body: some View
Text("View1")
struct View2: View
var body: some View
Text("View2")
【讨论】:
以上是关于使用 @State 变量不适用于从子视图更改 Body 中的视图状态的主要内容,如果未能解决你的问题,请参考以下文章
更改集合视图的 isHidden 属性不适用于搜索栏取消按钮
通过更改 SwiftUI 中的 @State 变量来刷新视图不起作用