异步加载数据时如何修复界面抖动(特别是刷新轮)?

问题描述 投票:0回答:1

我构建了一个 iPhone 应用程序来显示华盛顿特区地铁的列车时刻表和系统警报数据。

我有一个 Firebase 实时数据库,其中存储从 WMATA API 中提取的数据,我的应用程序异步加载数据并向用户显示。

应用程序运行正常,但有时界面有点不稳定,刷新轮在居中之前快速向左跳动,页面在数据加载之前快速闪烁空白。我认为这与我在刷新实际数据之前刷新界面的方式有关,这似乎是“正确”的做事方式,但使应用程序看起来比我想要的更加脱节。如果我能弄清楚如何防止刷新轮跳来跳去,我可能会没事,但我也很好奇是否有一个好的方法来防止加载 UI 元素(在本例中为“所有推文”)链接)直到异步数据加载完毕。

这是我的应用程序中的“警报”选项卡,在页面完全加载之前,它显示了跳跃的界面和不居中的“所有推文”链接的快速闪烁:

这是我尝试编写用于显示此页面的代码的更简单版本,该代码在页面加载时将来自 Firebase 的警报作为任务异步加载。

import SwiftUI
import FirebaseDatabase


class AlertListDebug: ObservableObject {
    @Published var alerts = [String:[String:Any]]()

    //Initializers
    init() {
        
    }
            
    //Get data asynchronously
    @MainActor
    func getAlertsDataDebug(refAlertsRaw: DatabaseReference!, officialTwitter: String) async {
        self.alerts = [:]
        
        //Generate query
        var query: DatabaseQuery
        query = refAlertsRaw.child("alerts").child("raw_" + officialTwitter)
        
        //Query data
        query.observeSingleEvent(of: .value) { snapshot  in
            if(!(snapshot.value is NSNull)) {
                let dict = snapshot.value as! [String: Any]
                for element in dict {
                    let key = element.key
                    let alertRaw = element.value as! [String: Any]
                    let alert = ["lines": alertRaw["Line"]!, "text": alertRaw["Text"]!]
                    
                    //Add alert element to list
                    self.alerts[key] = alert
                }
            }
        }
        
    }
}


struct AlertsViewDebug: View {
    @StateObject var alertList = AlertListDebug()
    
    //Variable tracking whether official or Twitter alerts are being shown
    @State var officialTwitter = "official"
    
    //Create database reference
    var refAlertsRaw: DatabaseReference! = Database.database().reference()
    
    var body: some View {
        VStack(alignment: .leading, spacing: 0){
            //Official and Twitter alert source buttons
            HStack {
                Button(action: {
                    officialTwitter = "official";
                    Task {
                        await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
                    }
                }) {
                    Text("Official Alerts")
                }
                Spacer()
                Button(action: {
                    officialTwitter = "twitter";
                    Task {
                        await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
                    }
                }) {
                    Text("Twitter Feed")
                }
            }
            //Display list of alerts
            ScrollView {
                VStack(spacing: 0) {
                    if(alertList.alerts.count > 0) {
                        ForEach(alertList.alerts.keys.sorted(), id: \.self) {alertKey in

                            Text(alertKey)
                                .font(.system(size: 16))
                                .foregroundColor(.black)
                                .frame(width: 320)
                            
                        }
                    }
                }.overlay(
                    RoundedRectangle(cornerRadius: 10)
                        .stroke(.black, lineWidth: 1)
                )
                .padding(.vertical, 5)
                if(officialTwitter == "twitter") {
                    //Browser link to Twitter feed
                    Text("All Tweets")
                }
            }.task {
                await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
            }.refreshable {
                await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw, officialTwitter: officialTwitter)
            }
            Spacer()
        }.navigationTitle("Alerts")
        .navigationBarTitleDisplayMode(.inline)
    }
}

如果我的做法有误,请告诉我 - 谢谢!

ios swift asynchronous firebase-realtime-database swiftui
1个回答
0
投票

显然这是由您在alertList上获取更新引起的,该更新速度非常快并导致ui刷新(https://github.com/pointfreeco/swift-composable-architecture/discussions/2542)。

您可以使用睡眠来解决它,但这不是理想的解决方案。 我也有类似的问题,还没解决。

.refreshable {
    try? await Task.sleep(nanoseconds: 1_000_000_000)
    await alertList.getAlertsDataDebug(refAlertsRaw: refAlertsRaw,officialTwitter: officialTwitter)
}
© www.soinside.com 2019 - 2024. All rights reserved.