ios - SwiftUI:在设备方向上重绘会使计时器无效
问题描述
我正在使用 SwiftUI 制作秒表。
出于设计目的,我在方向更改时重新绘制 UI,但这会使我的计时器无效。我使用了其中一种解决方案
如何在方向更改时保持计时器?
这是模型:
class Model: ObservableObject {
@Published var isLandScape: Bool = false
@Published var isPhone: Bool = UIDevice.current.userInterfaceIdiom == .phone
@Published var isPhoneAndLandscape: Bool = false;
}
自定义 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)
}
}
我在 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()
}
}
还有秒表类:
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"
}
}
编辑这是秒表在视图中的使用方式
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
)
}
}
}
}
解决方案
由于您StopWatch
是视图中的属性,因此每次创建视图的新实例时都会创建秒表的新实例,例如当设备布局更改时。
您的秒表应该是您的财产Model
。你的Model
实例存在于环境中,所以它的生命周期就是宿主视图控制器的生命周期:
class Model: ObservableObject {
@Published var isLandScape: Bool = false
@Published var isPhone: Bool = UIDevice.current.userInterfaceIdiom == .phone
@Published var isPhoneAndLandscape: Bool = false;
var stopwatch = StopWatch()
}
推荐阅读
- android - Android WebViewClient / WebViewAssetLoader 实现错误
- c - 如何在扫雷小游戏中插入自定义地雷?
- c# - 异步编程中如何使用await、async和Task
- react-native - 如何在原生反应中正确使用嵌入式 HTML 代码?
- json - Bittrex INVALID_MARKET_ORDER
- java - 如何在类图中的子类中呈现抽象方法
- flutter - 在 null 上调用了 setter 'phone='。I/flutter (32048):接收器:null I/flutter (32048):尝试调用:phone="48787487"
- flutter - 水平排列多个图像(颤动)
- reactjs - 在 TypeScript 的 React 组件中实现“as”prop
- javascript - AWS 上托管的静态网站中的环境变量