使用tabview更改选项卡时如何使SwiftUI中的计时器保持触发

Posted

技术标签:

【中文标题】使用tabview更改选项卡时如何使SwiftUI中的计时器保持触发【英文标题】:How to make a timer in SwiftUI keep firing when changing tab with tabview 【发布时间】:2020-01-20 03:02:10 【问题描述】:

我有一个计时器,它每半秒触发一次,这会导致调用一个函数,该函数输出一组字符串,用于显示特定日期的倒计时。当我创建一个新事件然后切换到包含倒计时信息的选项卡时它可以工作,但是当我切换回添加事件选项卡然后返回时它会停止倒计时。

计时器是用这个制作的:

    let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()

稍后使用它运行

ForEach(eventNames.indices, id: \.self)  index in


                    VStack
                        Text("Your event " + "\(self.eventNames[index])" + " is in " + "\(self.string[index])")
                        .onReceive(self.timer)  input in
                        self.differenceDate(numbers: index)

                        
                    


                

最后,它调用了这个函数

func differenceDate(numbers: Int) 
        self.formatter.unitsStyle = .full
        self.formatter.allowedUnits = [.day, .hour, .minute, .second]
        //self.formatter.maximumUnitCount = 2
        self.now = Date();
        if self.now > self.eventDates[numbers] 
            self.eventNames[numbers] = "";
        
        else 
        self.string[numbers] = self.formatter.string(from: self.now, to: self.eventDates[numbers]) ?? ""
        

        

这是完整的代码


import SwiftUI

struct ContentView: View 
    @State private var selection = 0
    @State private var eventDates = [Date]()
    @State private var eventNames = [String]()
    @State private var currentName = "";
    @State private var counter = 0;
    @State private var placeholderText = "Event Name";
    @State private var selectedDate = Date();
    var numbers = 0;
    let timer = Timer.publish(every: 0.5, on: .main, in: .common).autoconnect()
    @State var now = Date();
    @State var string = [String]();
    var formatter = DateComponentsFormatter();
    func differenceDate(numbers: Int) 
        self.formatter.unitsStyle = .full
        self.formatter.allowedUnits = [.day, .hour, .minute, .second]
        //self.formatter.maximumUnitCount = 2
        self.now = Date();
        if self.now > self.eventDates[numbers] 
            self.eventNames[numbers] = "";
        
        else 
        self.string[numbers] = self.formatter.string(from: self.now, to: self.eventDates[numbers]) ?? ""
        

        
    var body: some View 
        TabView(selection: $selection)
            //Page 1
            VStack
                Text("Add New Event")
                .underline()
                .font(.title)
                .padding(15)


//                        .onReceive(self.timer)  input in
//                        self.differenceDate(numbers: index)
//                        //
//                        
                  //  .minimumScaleFactor(0.1)




                TextField("\(placeholderText)", text: $currentName)
                .padding(10)
                .overlay(
                    RoundedRectangle(cornerRadius: 5)
                        .stroke(Color.gray, lineWidth: 1)
                    .padding(5)
                )



               Text("When is your event?")
                DatePicker("Please enter a date", selection: $selectedDate, displayedComponents: .date)
                    .labelsHidden()
                    .scaledToFill()
                Button(action: 
                    if self.currentName != "" 
                    self.eventNames.append(self.currentName)
                    self.eventDates.append(self.selectedDate)
                    self.string.append("")

                    self.currentName = "";
                    

                )

                
                    Text("Add Event")
                        .font(.headline)
                        .foregroundColor(.black)
                
                .padding(25)

                .overlay(
                    RoundedRectangle(cornerRadius: 5)
                    .stroke(Color.gray, lineWidth: 3)
                    .padding(5)
                )



            
                //Tab 1
                .tabItem 
                    VStack 
                        Image(systemName: "calendar")
                        Text("Add Event")
                    
                
                .tag(1)

            //Page 2
            VStack

                Text("Your Events").underline()
                .font(.title)
                .padding(15)


                ForEach(eventNames.indices, id: \.self)  index in


                    VStack
                        Text("Your event " + "\(self.eventNames[index])" + " is in " + "\(self.string[index])")
                        .onReceive(self.timer)  input in
                        self.differenceDate(numbers: index)

                        
                    


                


            

                //Tab 2
                .font(.title)
                .tabItem 
                    VStack 
                        Image(systemName: "flame.fill")
                        Text("Countdowns")
                    
                
                .tag(0)
        
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView()
    


我想知道是否有解决方法,或者如何在选项卡更改时保持计时器触发,或者在选项卡更改时暂停它,然后在切换回选项卡时重新启动它。

【问题讨论】:

【参考方案1】:

它需要将.onReceive附加到TabView,它将在所有选项卡上接收,例如

TabView 
...
// << all tab items here
...

.onReceive(self.timer)  _ in
    self.differenceDate()

并在处理程序内部迭代索引

func differenceDate() 
   for numbers in eventNames.indices 
     // current body here
   

【讨论】:

以上是关于使用tabview更改选项卡时如何使SwiftUI中的计时器保持触发的主要内容,如果未能解决你的问题,请参考以下文章

使用 SwiftUI 的 TabbedView 切换到其他选项卡时查看内容不显示

SwiftUI:再次轻按选定的选项卡时,弹出到根视图

从一个选项卡滑动到另一个选项卡时,TabView 不保留状态

SwiftUI - 如何将工具栏添加到 NavigationView 内的 TabView 选项卡?

标签视图导航上的 SwiftUI 调用功能

更改 TabView (SwiftUI) 中未选中图标的颜色