gpt4 book ai didi

ios - 在 SwiftUI 中创建新父级时 subview 不会重置

转载 作者:行者123 更新时间:2023-12-01 16:11:31 26 4
gpt4 key购买 nike

我昨天发了一篇关于这个的帖子,并为它不够清晰或描述性不够深表歉意。今天我在这个问题上取得了一些进展,但仍然没有找到解决方案。
在我的程序中,我有一个名为 GameView() 的主视图、一个名为 KeyboardView() 的 View 和一个名为 ButtonView() 的 View 。
ButtonView() 是一个简单的按钮,它显示一个字母,按下时告诉键盘 View 它属于它所代表的字母。当它被按下时,它也会被关闭,因此不能再次按下它。这是代码。

struct ButtonView: View {

let impactFeedbackgenerator = UIImpactFeedbackGenerator(style: .medium)
var letter:String
var function:() -> Void
@State var pressed = false

var body: some View {
ZStack{

Button(action: {
if !self.pressed {
self.pressed = true

self.impactFeedbackgenerator.prepare()
self.impactFeedbackgenerator.impactOccurred()

self.function()
}
}, label: {
if pressed{
Text(letter)
.font(Font.custom("ComicNeue-Bold", size: 30))
.foregroundColor(.white)
.opacity(0.23)
} else if !pressed{
Text(letter)
.font(Font.custom("ComicNeue-Bold", size: 30))
.foregroundColor(.white)
}
})
}.padding(5)
}
}
键盘 View 是 ButtonViews() 的集合,键盘上的每个按钮对应一个。如果按下按钮,它会告诉 GameView 按下了哪个按钮。
struct KeyboardView: View {

@Environment(\.parentFunction) var parentFunction

var topRow = ["Q","W","E","R","T","Y","U","I","O","P"]
var midRow = ["A","S","D","F","G","H","J","K","L"]
var botRow = ["Z","X","C","V","B","N","M"]


var body: some View {
VStack{

HStack(){
ForEach(0..<topRow.count, id: \.self){i in
ButtonView(letter: self.topRow[i], function: {self.makeGuess(self.topRow[i])})
}
}

HStack(){
ForEach(0..<midRow.count, id: \.self){i in
ButtonView(letter: self.midRow[i], function: {self.makeGuess(self.midRow[i])})
}
}

HStack(){
ForEach(0..<botRow.count, id: \.self){i in
ButtonView(letter: self.botRow[i], function: {self.makeGuess(self.botRow[i])})
}
}
}
}

func makeGuess(_ letter:String){
print("Keyboard: Guessed \(letter)")
self.parentFunction?(letter)
}
}
最后一个 GameView() 是键盘所属的地方。它显示键盘以及假定的游戏的其余部分。
struct GameView: View {

@Environment(\.presentationMode) var presentation

@State var guessedLetters = [String]()
@State var myKeyboard:KeyboardView = KeyboardView()

var body: some View {
ZStack(){

Image("Background")
.resizable()
.edgesIgnoringSafeArea(.all)
.opacity(0.05)

VStack{
Button("New Game") {

self.newGame()

}.font(Font.custom("ComicNeue-Bold", size: 20))
.foregroundColor(.white)
.padding()

self.myKeyboard
.padding(.bottom, 20)

}
}.navigationBarTitle("")
.navigationBarBackButtonHidden(true)
.navigationBarHidden(true)
.environment(\.parentFunction, parentFunction)
}

func makeGuess(_ letter:String){
self.guessedLetters.append(letter)
}

func newGame(){
print("Started a new game.")

self.guessedLetters.removeAll()
self.myKeyboard = KeyboardView()
}


func parentFunction(_ letter:String) {
makeGuess(letter)
}
}

struct ParentFunctionKey: EnvironmentKey {
static let defaultValue: ((_ letter:String) -> Void)? = nil
}

extension EnvironmentValues {
var parentFunction: ((_ letter:String) -> Void)? {
get { self[ParentFunctionKey.self] }
set { self[ParentFunctionKey.self] = newValue }
}
}
问题是当我开始一个新游戏时,数组被重置但keyboardView()没有重置,已经关闭的按钮仍然关闭,但是由于它被新的keyboardView()取代,它们不应该回到原来的状态开启?

最佳答案

我将重复我在 answer 中所说的话对于您之前的问题-在大多数正常用例下,您不应将 View 实例化为变量,因此,如果您发现自己这样做,则可能走错了路。

每当有任何状态变化时,SwiftUI 都会重新计算主体并重建 View 树,并将 subview 状态与新树匹配。
当它检测到某些东西发生了变化时,它意识到新的 subview 确实是新的,所以它重置它的状态,触发 .onAppear等等。但是当它无法检测到任何变化时,它只会为所有后代 View 保持相同的状态。
这就是你正在观察的。
具体来说,在您的情况下,结构上没有任何变化 - 即它仍然是:

GameView
--> KeyboardView
--> ButtonView
ButtonView
ButtonView
...
所以,它保持 ButtonView的状态照原样。
您可以向 SwiftUI 发出信号,表明 View 实际上已经更改,并且应该使用 .id 进行更新。修饰符(文档不是很好,但您可以在博客中找到更多信息),您需要在其中提供任何 Hashable与当前变量不同的变量,以便重置它。
我将使用新的 Bool以变​​量为例:
struct GameView {
@State var id: Bool = false // initial value doesn't matter

var body: some View {
VStack() {
KeyboardView()
.id(id) // use the id here
Button("new game") {
self.id.toggle() // changes the id
}
}
}
}
每次 id变化,SwiftUI 重置状态,所以所有的 subview ,比如 ButtonView s',状态被重置。

关于ios - 在 SwiftUI 中创建新父级时 subview 不会重置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63222420/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com