SwiftUI实例@State变量
我对SwiftUI还是个新手。我有一个“计数器”视图,它每秒钟计数一次。当颜色改变时,我想“重置”计数器:SwiftUI实例@State变量,swift,state,swiftui,reset,Swift,State,Swiftui,Reset,我对SwiftUI还是个新手。我有一个“计数器”视图,它每秒钟计数一次。当颜色改变时,我想“重置”计数器: struct MyCounter : View { let color: Color @State private var count = 0 init(color:Color) { self.color = color _count = State(initialValue: 0) } var body: some View { Text(
struct MyCounter : View {
let color: Color
@State private var count = 0
init(color:Color) {
self.color = color
_count = State(initialValue: 0)
}
var body: some View {
Text("\(count)").foregroundColor(color)
.onAppear(){
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.count = self.count + 1 }
}
}
}
以下是我使用计数器的主要视图:
struct ContentView: View {
@State var black = true
var body: some View {
VStack {
MyCounter(color: black ? Color.black : Color.yellow)
Button(action:{self.black.toggle()}) { Text("Toggle") }
}
}
}
当我单击“切换”按钮时,我看到调用了MyCounter构造函数,但@State计数器仍然存在,并且从不重置。所以我的问题是如何重置这个@State值?请注意,我不希望使用counter作为@Binding并在父视图中管理它,而是希望MyCounter是一个自包含的小部件。(这是一个简化的示例。我正在创建的真正的小部件是一个执行精灵动画的精灵动画师,当我交换图像时,我希望动画师从第0帧开始)。谢谢 您需要一个绑定变量:
struct MyCounter : View {
let color: Color
@Binding var count: Int
var body: some View {
Text("\(count)").foregroundColor(color)
.onAppear(){
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.count = self.count + 1 }
}
}
}
struct ContentView: View {
@State var black = true
@State var count : Int = 0
var body: some View {
VStack {
MyCounter(color: black ? Color.black : Color.yellow , count: $count)
Button(action:{self.black.toggle()
self.count = 0
}) { Text("Toggle") }
}
}
}
如果您不喜欢绑定,也可以只添加一个状态值innerColor
struct MyCounter : View {
let color: Color
@State private var count: Int = 0
@State private var innerColor: Color?
init(color: Color) {
self.color = color
}
var body: some View {
return Text("\(self.count)")
.onAppear(){
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.count = self.count + 1 }
}.foregroundColor(color).onReceive(Just(color), perform: { color in
if self.innerColor != self.color {
self.count = 0
self.innerColor = color}
})
}
}
您需要一个绑定变量:
struct MyCounter : View {
let color: Color
@Binding var count: Int
var body: some View {
Text("\(count)").foregroundColor(color)
.onAppear(){
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.count = self.count + 1 }
}
}
}
struct ContentView: View {
@State var black = true
@State var count : Int = 0
var body: some View {
VStack {
MyCounter(color: black ? Color.black : Color.yellow , count: $count)
Button(action:{self.black.toggle()
self.count = 0
}) { Text("Toggle") }
}
}
}
如果您不喜欢绑定,也可以只添加一个状态值innerColor
struct MyCounter : View {
let color: Color
@State private var count: Int = 0
@State private var innerColor: Color?
init(color: Color) {
self.color = color
}
var body: some View {
return Text("\(self.count)")
.onAppear(){
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in self.count = self.count + 1 }
}.foregroundColor(color).onReceive(Just(color), perform: { color in
if self.innerColor != self.color {
self.count = 0
self.innerColor = color}
})
}
}
有两种方法可以解决这个问题。一种是使用绑定,如E.Coms所解释的,这是解决问题的最简单方法 或者,您可以尝试使用
observateObject
作为计时器的视图模型。这是更灵活的解决方案。计时器可以传递,如果您愿意,也可以作为环境对象注入
class TimerModel:ObservableObject{
//@Published属性包装器确保自动发出objectWillChange信号。
@已发布变量计数:Int=0
init(){}
func start(){
scheduledTimer(withTimeInterval:1,repeats:true){in self.count=self.count+1}
}
函数重置(){
计数=0
}
}
然后,您的计时器视图将变为
struct MyCounter:视图{
让颜色:颜色
@ObservedObject变量计时器:TimerModel
初始化(颜色:颜色,计时器:TimerModel){
self.color=颜色
self.timer=计时器
}
var body:一些观点{
文本(“\(timer.count)”).foregroundColor(颜色)
.onAppear(){
self.timer.start()
}
}
}
您的内容视图变为
struct ContentView:View{
@状态变量black=true
@ObservedObject var timer=TimerModel()
var body:一些观点{
VStack{
MyCounter(颜色:黑色?颜色。黑色:颜色。黄色,计时器:self.timer)
按钮(操作:{
self.black.toggle()
self.timer.reset()
}) {
文本(“切换”)
}
}
}
}
使用可观察对象的优点是,您可以更好地跟踪计时器。您可以向模型中添加一个stop()
方法,该方法会使计时器无效,您可以在视图的onDisappear
块中调用它
对于这种方法,您必须注意的一点是,当您以独立方式使用计时器时,您可以使用MyCounter(颜色:…,timer:TimerModel())在视图生成器闭包中创建它,每次重新渲染视图时,都会替换计时器模型,因此,您必须确保以某种方式保留模型。有两种方法可以解决此问题。一种是使用绑定,如E.Coms所解释的,这是解决问题的最简单方法 或者,您可以尝试使用
observateObject
作为计时器的视图模型。这是更灵活的解决方案。计时器可以传递,如果您愿意,也可以作为环境对象注入
class TimerModel:ObservableObject{
//@Published属性包装器确保自动发出objectWillChange信号。
@已发布变量计数:Int=0
init(){}
func start(){
scheduledTimer(withTimeInterval:1,repeats:true){in self.count=self.count+1}
}
函数重置(){
计数=0
}
}
然后,您的计时器视图将变为
struct MyCounter:视图{
让颜色:颜色
@ObservedObject变量计时器:TimerModel
初始化(颜色:颜色,计时器:TimerModel){
self.color=颜色
self.timer=计时器
}
var body:一些观点{
文本(“\(timer.count)”).foregroundColor(颜色)
.onAppear(){
self.timer.start()
}
}
}
您的内容视图变为
struct ContentView:View{
@状态变量black=true
@ObservedObject var timer=TimerModel()
var body:一些观点{
VStack{
MyCounter(颜色:黑色?颜色。黑色:颜色。黄色,计时器:self.timer)
按钮(操作:{
self.black.toggle()
self.timer.reset()
}) {
文本(“切换”)
}
}
}
}
使用可观察对象的优点是,您可以更好地跟踪计时器。您可以向模型中添加一个stop()
方法,该方法会使计时器无效,您可以在视图的onDisappear
块中调用它
对于这种方法,您必须注意的一点是,当您以独立方式使用计时器时,您可以使用MyCounter(颜色:…,timer:TimerModel())在视图生成器闭包中创建它,每次重新渲染视图时,都会替换计时器模型,因此,你必须确保以某种方式保留模型。谢谢,但这是我不想要的一个解决方案(在帖子中提到)。如果MyCounter是“独立的”,那就太好了。谢谢。我想第二种选择是正确的。遗憾的是,没有简单的方法来重新初始化状态值。谢谢,但这是我不想要的一个解决方案(在文章中提到)。如果MyCounter是“独立的”,那就太好了。谢谢。我想第二种选择是正确的。遗憾的是,没有简单的方法来重新初始化状态值。你能解释为什么会出现这种情况吗?W