Swiftui 如何禁用父视图的`onAppear`方法?
我目前正在使用SwiftUI开发一个应用程序 我正在尝试制作一个计时器应用程序,我想知道如何禁用父视图的Swiftui 如何禁用父视图的`onAppear`方法?,swiftui,Swiftui,我目前正在使用SwiftUI开发一个应用程序 我正在尝试制作一个计时器应用程序,我想知道如何禁用父视图的onApear方法或解决我现在遇到的问题的任何方法 当我使用Binding值从父视图(ListView)导航到详细视图时,onAppear方法工作,然后在我的代码中重置Binding值 如果我没有使用方法(func setTimer()在我的代码中)在onAppear中初始化ListRow,绑定值工作正常,但是当我看到第一个视图时,我无法显示初始时间值 我如何解决这个问题 代码如下: 斯威夫
onApear
方法或解决我现在遇到的问题的任何方法
当我使用Binding
值从父视图(ListView)导航到详细视图时,onAppear
方法工作,然后在我的代码中重置Binding
值
如果我没有使用方法(func setTimer()
在我的代码中)在onAppear
中初始化ListRow,绑定值工作正常,但是当我看到第一个视图时,我无法显示初始时间值
我如何解决这个问题
代码如下: 斯威夫特时代酒店
import SwiftUI
@main
struct TimerApp: App {
@ObservedObject var timeManager = TimeManager()
var body: some Scene {
WindowGroup {
ListTimerView()
.environmentObject(timeManager)
}
}
}
斯威夫特时间经理
import SwiftUI
class TimeManager: ObservableObject {
@Published var multipleTimers:[MultipleTimer] = [
MultipleTimer( hourSelection: 0, minSelection: 2, secSelection: 0),
MultipleTimer( hourSelection: 0, minSelection: 0, secSelection: 30),
MultipleTimer( hourSelection: 1, minSelection: 30, secSelection: 0)
]
var timer = Timer.publish(every: 0.05, on: .main, in: .common).autoconnect()
}
enum TimeFormat {
case hr
case min
case sec
}
enum TimerStatus {
case running
case pause
case stopped
}
struct MultipleTimer:Hashable {
var hourSelection: Int
var minSelection: Int
var secSelection: Int
}
ListTimerView.swift
import SwiftUI
struct ListTimerView: View {
@EnvironmentObject var timeManager:TimeManager
@State var isAddSheet = false
var body: some View {
NavigationView(){
VStack{
ForEach(timeManager.multipleTimers, id:\.self){multipleTimer in
ListTimerRow(hourSelection: multipleTimer.hourSelection, minSelection: multipleTimer.minSelection, secSelection: multipleTimer.secSelection)
}
}
}
}
}
import SwiftUI
struct DetailTimerView: View {
@EnvironmentObject var timeManager:TimeManager
@Binding var hourSelection: Int
@Binding var minSelection: Int
@Binding var secSelection: Int
@Binding var duration: Double
@Binding var displayedTimeFormat: TimeFormat
var body: some View {
VStack{
Text(self.displayTimer())
.font(.title)
}
}
func displayTimer() -> String {
let hr = Int(duration) / 3600
let min = Int(duration) % 3600 / 60
let sec = Int(duration) % 3600 % 60
switch displayedTimeFormat {
case .hr:
return String(format: "%02d:%02d:%02d", hr, min, sec)
case .min:
return String(format: "%02d:%02d", min, sec)
case .sec:
return String(format: "%02d:%02d", min, sec)
}
}
}
ListTimerRow.swift
import SwiftUI
struct ListTimerRow: View {
@EnvironmentObject var timeManager:TimeManager
@State var hourSelection: Int
@State var minSelection: Int
@State var secSelection: Int
@State var duration: Double = 0
@State var maxValue: Double = 0
@State var displayedTimeFormat: TimeFormat = .min
@State var timerStatus: TimerStatus = .stopped
var body: some View {
NavigationLink(destination:DetailTimerView(
hourSelection: $hourSelection, minSelection: $minSelection, secSelection: $secSelection,
duration:$duration, displayedTimeFormat:$displayedTimeFormat
)){
VStack{
HStack{
Text(self.displayTimer())
.font(.title)
Spacer()
Image(systemName: "stop.circle.fill")
.font(.title)
.opacity(self.timerStatus == .stopped ? 0.1 : 1)
.onTapGesture {
if timerStatus != .stopped {
self.stop()
}
}
Image(systemName: self.timerStatus == .running ? "pause.circle.fill" : "play.circle.fill")
.font(.title)
.opacity(self.hourSelection == 0 && self.minSelection == 0 && self.secSelection == 0 ? 0.1 : 1)
.onTapGesture {
if timerStatus == .stopped {
self.setTimer()
}
if duration != 0 && timerStatus != .running {
self.start()
} else if timerStatus == .running {
self.pause()
}
}
}
Divider()
}
}
.padding()
.onAppear(){
self.setTimer()
print("onAppear checked")
}
.onReceive(timeManager.timer) { _ in
guard self.timerStatus == .running else { return }
if self.duration > 0 {
self.duration -= 0.05
} else {
self.timerStatus = .stopped
}
}
}
func setTimer() {
duration = Double(hourSelection * 3600 + minSelection * 60 + secSelection)
maxValue = duration
if duration < 60 {
displayedTimeFormat = .sec
} else if duration < 3600 {
displayedTimeFormat = .min
} else {
displayedTimeFormat = .hr
}
}
func displayTimer() -> String {
let hr = Int(duration) / 3600
let min = Int(duration) % 3600 / 60
let sec = Int(duration) % 3600 % 60
switch displayedTimeFormat {
case .hr:
return String(format: "%02d:%02d:%02d", hr, min, sec)
case .min:
return String(format: "%02d:%02d", min, sec)
case .sec:
return String(format: "%02d:%02d", min, sec)
}
}
func start() {
timerStatus = .running
}
func pause() {
timerStatus = .pause
}
func stop() {
timerStatus = .stopped
duration = maxValue
}
}
Xcode:12.0.1版 iOS:14.0
生命周期:SwiftUI应用程序您不应该使用onAppear,但需要在类似于下面示例的init方法中设置状态的初始值:
self._duration = State(initialValue: initialDurationValue)
例如,ListTimerRow的init方法可能如下所示,您不需要在onAppear中调用setTimer方法
init () {
let d = Double(hourSelection * 3600 + minSelection * 60 + secSelection)
_duration = State(initialValue: d)
_maxValue = State(initialValue: d)
if d < 60 {
displayedTimeFormat = State(initialValue: .sec)
} else if d < 3600 {
displayedTimeFormat = State(initialValue: .min)
} else {
displayedTimeFormat = State(initialValue: .hr)
}
}
init(){
设d=Double(小时选择*3600+分钟选择*60+秒选择)
_持续时间=状态(初始值:d)
_maxValue=状态(初始值:d)
如果d<60{
displayedTimeFormat=状态(初始值:。秒)
}否则,如果d<3600{
displayedTimeFormat=状态(初始值:.min)
}否则{
displayedTimeFormat=状态(初始值:.hr)
}
}
我尝试了一些解决方案,最后选择了这种方式
.onAppear(){
if timerStatus == .stopped {
self.setTimer()
}
}
我不确定我是否理解你的问题。你能缩小范围,让它更具体吗?@pawello2222,我需要使用
self.setTimer()
但是当导航到DetailTimerView
时,计时器运行后,DetailTimerView
中的绑定值会被重置。谢谢你的回答,有没有办法使用整个setTimer()
方法而不使用onAppear方法?@Tio我已经更新了我的答案谢谢你的更新,我终于解决了这个问题,因为我发布了答案。谢谢你的支持!