[英]SwiftUI's onAppear() and onDisappear() called multiple times and inconsistently on Xcode 12.1
I've come across some strange behavior with SwiftUI's onAppear()
and onDisappear()
events.我在 SwiftUI 的
onAppear()
和onDisappear()
事件中遇到了一些奇怪的行为。 I need to be able to reliably track when a view is visible to the user, disappears, and any other subsequent appear/disappear events (the use case is tracking impressions for mobile analytics).我需要能够可靠地跟踪视图何时对用户可见、消失以及任何其他后续出现/消失事件(用例是跟踪移动分析的印象)。
I was hoping to leverage the onAppear()
and onDisappear()
events associated with swiftUI views, but I'm not seeing consistent behavior when using those events.我希望利用与 swiftUI 视图关联的
onAppear()
和onDisappear()
事件,但在使用这些事件时我没有看到一致的行为。 The behavior can change depending on view modifiers as well as the simulator on which I run the app.行为可能会根据视图修改器以及我运行应用程序的模拟器而改变。
In the example code listed below, I would expect that when ItemListView2
appears, I would see the following printed out in the console:在下面列出的示例代码中,我希望当
ItemListView2
出现时,我会在控制台中看到以下内容:
button init
button appear
And on the iPhone 8 simulator, I see exactly that.在 iPhone 8 模拟器上,我完全看到了这一点。
However, on an iPhone 12 simulator, I see:但是,在 iPhone 12 模拟器上,我看到:
button init
button appear
button disappear
button appear
Things get even weirder when I enable the listStyle
view modifier:当我启用
listStyle
视图修饰符时,事情变得更加奇怪:
button init
button appear
button disappear
button appear
button disappear
button appear
button appear
The iPhone 8, however remains consistent and produces the expected result.然而,iPhone 8 保持一致并产生了预期的结果。
I should also note that in no case, did the Button ever seem to disappear and re-appear to the eye.我还应该指出,在任何情况下,按钮似乎都不会消失并重新出现在眼前。
These inconsistencies are also not simulator only issues, i noticed them on devices as well.这些不一致也不只是模拟器的问题,我在设备上也注意到了它们。
I need to reliably track these appear/disappear events.我需要可靠地跟踪这些出现/消失的事件。 For example I'd need to know when a cell in a list appears (scrolled into view) or disappears (scrolled out of view) or when, say a user switches tabs.
例如,我需要知道列表中的单元格何时出现(滚动到视图中)或消失(滚动出视图)或何时,比如说用户切换选项卡。
Has anyone else noticed this behavior?有没有其他人注意到这种行为? To me this seems like a bug in SwiftUI, but I'm not certain as I've not used SwiftUI enough to trust myself to discern a programmer error from an SDK error.
对我来说,这似乎是 SwiftUI 中的一个错误,但我不确定,因为我没有充分使用 SwiftUI 来相信自己能够从 SDK 错误中辨别出程序员错误。 If any of you have noticed this, did you find a good work-around / fix?
如果你们中有人注意到这一点,您是否找到了一个好的解决方法/修复方法?
Thanks,谢谢,
// Sample code referenced in explanation
// Using Xcode Version 12.1 (12A7403) and iOS 14.1 for all simulators
import SwiftUI
struct ItemListView2: View {
let items = ["Cell 1", "Cell 2", "Cell 3", "Cell 4"]
var body: some View {
ListingView(items: items)
}
}
private struct ListingView: View {
let items: [String]
var body: some View {
List {
Section(
footer:
FooterButton()
.onAppear { print("button appear") }
.onDisappear { print("button disappear") }
) {
ForEach(items) { Text($0) }
}
}
// .listStyle(GroupedListStyle())
}
}
private struct FooterButton: View {
init() {
print("button init")
}
var body: some View {
Button(action: {}) { Text("Button") }
}
}
In SwiftUI you don't control when items in a List
appear or disappear .在 SwiftUI 中,您无法控制
List
中的项目何时出现或消失。 The view graph is managed internally by SwiftUI and views may appear/disappear at any time.视图图由 SwiftUI 内部管理,视图可能随时出现/消失。
You can, however, attach the onAppear
/ onDisappear
modifiers to the outermost view:但是,您可以将
onAppear
/ onDisappear
修饰符附加到最外面的视图:
List {
Section(footer: FooterButton()) {
ForEach(items, id: \.self) {
Text($0)
}
}
}
.listStyle(GroupedListStyle())
.onAppear { print("list appear") }
.onDisappear { print("list disappear") }
Try this UIKit approach.试试这个 UIKit 方法。 Similar behavior continues to exist under iOS 14.
类似行为在 iOS 14 下继续存在。
protocol RemoteActionRepresentable: AnyObject {
func remoteAction()
}
struct UIKitAppear: UIViewControllerRepresentable {
let action: () -> Void
func makeUIViewController(context: Context) -> UIAppearViewController {
let vc = UIAppearViewController()
vc.delegate = context.coordinator
return vc
}
func updateUIViewController(_ controller: UIAppearViewController, context: Context) {}
func makeCoordinator() -> Coordinator {
Coordinator(action: self.action)
}
class Coordinator: RemoteActionRepresentable {
var action: () -> Void
init(action: @escaping () -> Void) {
self.action = action
}
func remoteAction() {
action()
}
}
}
class UIAppearViewController: UIViewController {
weak var delegate: RemoteActionRepresentable?
override func viewDidLoad() {
view.addSubview(UILabel())
}
override func viewDidAppear(_ animated: Bool) {
delegate?.remoteAction()
}
}
extension View {
func onUIKitAppear(_ perform: @escaping () -> Void) -> some View {
self.background(UIKitAppear(action: perform))
}
}
Example:例子:
var body: some View {
MyView().onUIKitAppear {
print("UIViewController did appear")
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.