Estou brincando com o SwiftUI para tentar entender melhor, mas não consigo entender essa diferença de comportamento. Neste código de exemplo, por que a visualização struct pode girar enquanto a função @ViewBuilder não gira?
struct ContentView: View {
@State var isSpinning = false
var body: some View {
StructView()
funcView()
}
@ViewBuilder
func funcView() -> some View {
@State var isSpinning = false
VStack {
Button {
isSpinning.toggle()
}label: {
Text("Spin me")
}
Image(systemName: "arrow.clockwise")
.font(.system(size: 80))
.foregroundColor(.blue)
.rotationEffect(.degrees(isSpinning ? 360 : 0))
.animation(.easeInOut(duration: 1), value: isSpinning)
}
.padding()
}
struct StructView: View {
@State var isSpinning = false
var body: some View {
VStack {
Button {
isSpinning.toggle()
}label: {
Text("Spin me")
}
Image(systemName: "arrow.clockwise")
.font(.system(size: 80))
.foregroundColor(.blue)
.rotationEffect(.degrees(isSpinning ? 360 : 0))
.animation(.easeInOut(duration: 1), value: isSpinning)
}
.padding()
}
}
}
O fato de ser uma
@ViewBuilder
função, ou o fato de ser uma função separada, realmente não importa para o SwiftUI. É o mesmo que se você inlinefuncView
e colocasse diretamente no arquivobody
.E o problema disso é que
@State
não funciona como uma variável local . O SwiftUI não foi projetado para rastrear@State
s que são variáveis locais.@State
s sempre devem ser declarados como propriedades de instância em umaView
estrutura.No seu código, você também fez isso. Você declarou
@State var isSpinning = false
diretamente inContentView
, mas declarou novamente infuncView
, portanto, as referências aisSpinning
infuncView
são todas resolvidas para o@State
in declaradofuncView
.Você deve remover a linha
@State var isSpinning = false
infuncView
e agora as referências aisSpinning
serão resolvidas para aquela declarada emContentView
e a visualização funcionará conforme o esperado.Observe que há uma diferença entre escrever tudo
body
(chamar@ViewBuilder
fundos/propriedades é efetivamente equivalente a isso) e separar os componentes da visualização emView
estruturas diferentes.Ao colocar as coisas em uma
View
estrutura separada, você cria efetivamente uma "barreira" para atualizações de visualização. Por exemplo,StructView.body
não será chamado toda vez que algo emContentView
mudar, poisStructView
não depende de nada emContentView
.Por outro lado,
funcView
será chamado toda vez que algoContentView
mudar, porque bem, você está literalmente chamando-oContentView.body
.Portanto, em geral, é melhor separar suas visualizações em
View
estruturas individuais, em vez de separar suas visualizações em@ViewBuilder func
s ou@ViewBuilder var
s individuais na mesmaView
estrutura. Dessa forma, uma atualização no topo da hierarquia de visualização não fará com que todo o resto também seja atualizado.Aqui eu adicionei alguns
print
s para demonstrar a diferença: