首页 > 解决方案 > 使用tabview更改选项卡时如何使SwiftUI中的计时器保持触发

问题描述

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

计时器是使用这个制作的:

    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()
    }
}

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

标签: iosxcodeforeachswiftuiuitabview

解决方案


它需要附加.onReceiveTabView并且它将在所有选项卡上收到,例如

TabView {
...
// << all tab items here
...
}
.onReceive(self.timer) { _ in
    self.differenceDate()
}

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

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

推荐阅读