[英]SwiftUI: Repaint on Device orientation invalidates Timer
I am making a stopwatch using SwiftUI.我正在使用 SwiftUI 制作秒表。
I repaint the UI on orientation change for design purposes but this invalidates my timer.出于设计目的,我在方向更改时重新绘制 UI,但这会使我的计时器无效。 I used one of these solutions
我使用了其中一种解决方案
How can I persist my timer on orientation change?如何在方向更改时保持计时器?
Here is the model:这是 model:
class Model: ObservableObject {
@Published var isLandScape: Bool = false
@Published var isPhone: Bool = UIDevice.current.userInterfaceIdiom == .phone
@Published var isPhoneAndLandscape: Bool = false;
}
The custom UIHostingController:自定义 UIHostingController:
extension Notification.Name {
static let my_onViewWillTransition = Notification.Name("MainUIHostingController_viewWillTransition")
}
class MyUIHostingController<Content> : UIHostingController<Content> where Content : View {
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
NotificationCenter.default.post(name: .my_onViewWillTransition, object: nil, userInfo: ["size": size])
super.viewWillTransition(to: size, with: coordinator)
}
}
That I use in the SceneDelegate:我在 SceneDelegate 中使用的:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = MyUIHostingController(rootView: HomeView().environmentObject(model))
self.window = window
window.makeKeyAndVisible()
}
}
And the stopwatch class:还有秒表 class:
class StopWatch: ObservableObject {
@Published var stopWatchTime: String = "00:00:00";
@Published var isPaused = true;
var timer = Timer()
private var counter: Int = 0
func start() {
isPaused.toggle();
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { timer in
self.counter += 1
self.stopWatchTime = StopWatch.convertCountToTimeString(counter: self.counter)
}
}
func pause() {
isPaused.toggle();
timer.invalidate()
}
func reset() {
self.timer.invalidate()
self.isPaused = true;
self.counter = 0;
self.stopWatchTime = "00:00:00"
}
}
Edit Here is how the stopwatch is used in the view编辑这是秒表在视图中的使用方式
struct StopWatchUI: View {
@ObservedObject var stopWatch = StopWatch()
@Binding var isSureToResetWatch: Bool;
@EnvironmentObject var model: Model
var body: some View {
return VStack {
Text(self.stopWatch.stopWatchTime)
.foregroundColor(.textPrimary)
.font(.custom("Courier",size: model.isPhoneAndLandscape ? 50 : 120))
.fontWeight(.heavy)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: nil, maxHeight: nil)
.padding(15)
.minimumScaleFactor(0.4)
.cornerRadius(5)
.lineLimit(1)
HStack {
StopWatchResetButton(isSureToResetWatch: $isSureToResetWatch, resetTime: self.stopWatch.reset)
Spacer()
StopWatchStartButton(
start: self.stopWatch.start,
pause: self.stopWatch.pause,
isStopWatchPaused: self.stopWatch.isPaused
)
}
}
}
}
As your StopWatch
is a property within your view, a new instance of your stopwatch is being created each time a new instance of your view is created, such as when the device layout changes.由于
StopWatch
是视图中的一个属性,因此每次创建视图的新实例时都会创建一个新的秒表实例,例如当设备布局更改时。
Your stopwatch should be a property of your Model
.您的秒表应该是您的
Model
的财产。 Your Model
instance lives in the environment, so its lifetime is the lifetime of the hosting view controller:您的
Model
实例存在于环境中,因此它的生命周期是托管视图 controller 的生命周期:
class Model: ObservableObject {
@Published var isLandScape: Bool = false
@Published var isPhone: Bool = UIDevice.current.userInterfaceIdiom == .phone
@Published var isPhoneAndLandscape: Bool = false;
var stopwatch = StopWatch()
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.