【发布时间】:2021-04-29 16:40:37
【问题描述】:
我需要开发一个具有排行榜功能的移动应用。排行榜只显示在一个选项卡上,但是,每次我从另一个选项卡返回此页面时,排行榜总是立即消失(请看这个screen record)。有没有办法让数据稳定显示?
这是我的代码 sn-p:
// LeaderboardView.swift
import SwiftUI
struct Leaderboard: View {
@ObservedObject private var users = UserViewModel()
var body: some View {
// ...
NavigationView {
List(users.topFiveUsers) {
user in
VStack {
HStack {
Text(verbatim: user.name).font(.headline)
Text(verbatim: String(user.xp)).font(.subheadline)
}
}
}
}
.navigationTitle(Text("Leaderboard"))
Spacer()
}
.background(Color.white)
}
}
struct Leaderboard_Previews: PreviewProvider {
static var previews: some View {
Leaderboard()
}
}
// UserViewModel.swift
import Foundation
import Firebase
import FirebaseFirestore
class UserViewModel: ObservableObject {
@Published var topFiveUsers = [User]()
private var db = Firestore.firestore().collection("Users")
public init() {
let top5 = db.order(by: "xp", descending: true).limit(to: 5)
top5.addSnapshotListener { (QuerySnapshot, error) in
guard let documents = QuerySnapshot?.documents else {
print("Document is empty")
return
}
self.topFiveUsers = documents.map {
(QueryDocumentSnapshot) -> User in
let data = QueryDocumentSnapshot.data()
let xp = data["xp"]
let name = data["username"]
return User(name:name as? String ?? "", xp:xp as? Int ?? 0)
}
}
}
}
// User.swift
import SwiftUI
import Firebase
class User : ObservableObject, Identifiable {
@Published var name = ""
@Published var bio = ""
@Published var interest = ""
@Published var level = 1
@Published var xp = 0
@Published var email = ""
@Published var image_Data = Data(count: 0)
@Published var picker = false
let ref = Firestore.firestore()
@Published var isLoading = false
@AppStorage("status") var status = false
// common init
init() {
}
//initializer for leaderboard collection
init(name: String, xp: Int) {
self.name = name
self.xp = xp
self.level = User.xp2Level(xp: xp)
}
}
// ContentView.swift
struct ContentView: View {
init() {
UITabBar.appearance().isHidden = true
}
@State var centerX : CGFloat = 0
@State var goToHome = false
@State var edge = UIApplication.shared.windows.first?.safeAreaInsets
// @Environement(.verticalSizeClass) var size
var body: some View {
ZStack {
if goToHome {
NavigationView {
CustomTabView(centerX: $centerX)
.navigationBarTitleDisplayMode(.inline)
.navigationBarHidden(true)
}
}
else {
OnBoardScreen()
}
}
.onReceive(NotificationCenter.default.publisher(for:Notification.Name("Success")), perform: {
_ in withAnimation{self.goToHome = true}
})
}
}
struct CustomTabView : View {
//swich tabs
@State var selectedTab = "home"
@Binding var centerX : CGFloat
var body : some View {
ZStack(alignment: Alignment(horizontal: .center, vertical: .bottom)){
TabView(selection: $selectedTab) {
Home()
.tag("home")
Leaderboard()
.tag("Leaderboard")
Pal()
.tag("profile")
}
// .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
.ignoresSafeArea(.all, edges: .all)
// Spacer()
HStack(spacing: 0) {
ForEach(tabs, id: \.self) {image in
GeometryReader {reader in
TabButton(image: image, centerX: $centerX, rect:reader.frame(in:.global), selectedTab: $selectedTab)
//setting initial curve
.onAppear(perform: {
if image == tabs.first{
centerX = reader.frame(in: .global).midX
}
})
}
.frame(width: 50, height: 30)
if image != tabs.last {Spacer(minLength: 0)}
}
}
.padding(.horizontal, 30)
// .padding(.top)
.padding(.vertical, 17)
.padding(.bottom, 20)
.padding(.bottom, UIApplication.shared.windows.first?.safeAreaInsets.bottom == 0 ? 15: 0)
.background(Color("5324FF").clipShape(AnimatedShape(centerX: centerX)))
.shadow(color: Color.blue.opacity(0.1), radius: 5, x: 0, y: -5)
// .ignoresSafeArea(.all, edges: .all)
}
.ignoresSafeArea(.all, edges: .all)
}
}
【问题讨论】:
-
这个问题与您处理显示视图的方式有关。用户对象、firebase 和排行榜本身的代码与问题无关。请发布代码,显示您如何显示不同的标签项。
-
感谢您的建议,我已经编辑了我的问题。请参考。
-
同意 xTwisteDx 所说的 - 问题在于您如何处理选项卡视图的选定状态。我建议将其设置在一个较小的复制案例中,这样您就不会被所有其他代码分心。另外,请不要手动映射 Firestore 数据 - 改用 Codable。我为此写了一份综合指南:peterfriese.dev/firestore-codable-the-comprehensive-guide。此外,请确保将 Firestore 文档 ID 与用户的 id 属性进行映射,以使其真正可识别。
标签: ios swift firebase swiftui frontend