You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决SwiftUI加载展示数据时视图抖动的问题?

解决SwiftUI视图因异步加载球队数据导致的抖动问题

你碰到的视图抖动,根源是API加载完成前,following_teams是空数组,对应的队徽HStack完全不显示;等数据加载完成后,这个HStack突然出现,挤压其他视图重新布局,再加上全局的.animation(.easeIn),就触发了整个视图的过渡动画,表现为抖动。

下面是几种有效的解决方法:

方法一:为动态视图预留固定占位空间

不管数据是否加载完成,都保留队徽区域的布局位置,避免布局突变。可以添加和实际队徽尺寸一致的占位视图:

修改Home视图中对应的队徽HStack部分:

HStack(spacing: 15) {
    if followingTeamsModel.following_teams.isEmpty {
        // 显示两个占位,和实际队徽尺寸匹配
        ForEach(0..<2) { _ in
            RoundedRectangle(cornerRadius: 15)
                .fill(Color.gray.opacity(0.1))
                .frame(width: 50, height: 50)
                .shadow(color: .black.opacity(0.08), radius: 5, x: 5, y: 5)
        }
    } else {
        ForEach(followingTeamsModel.following_teams, id: \.id) { items in
            KFImage(URL(string: "https://example.com/team_logo/\(items.logo_file ?? "")")!)
                .resizable()
                .scaledToFit()
                .cornerRadius(5)
                .padding(5)
                .frame(width: 50, height: 50)
                .background(Color.white)
                .shadow(color: .black.opacity(0.08), radius: 5, x: 5, y: 5)
                .cornerRadius(15)
        }
    }
}
.padding(.trailing, 10)

方法二:移除全局动画,仅给需要的元素加动画

全局的.animation(.easeIn)会让所有状态变化都触发动画,包括数据加载导致的布局变化。可以把全局动画去掉,只给队徽区域单独添加动画:

  1. 移除NavigationView后的.animation(.easeIn)
  2. 给队徽HStack添加条件动画:
HStack(spacing: 15) {
    // 原队徽循环渲染代码不变
}
.padding(.trailing, 10)
.animation(.easeIn, value: followingTeamsModel.following_teams)

这样只有当following_teams数据变化时,才会触发队徽区域的动画,不会影响整个视图布局。

方法三:提前加载数据

把数据加载的时机提前到视图初始化前,比如在ViewModel的初始化方法中就开始请求数据:

修改FollowingTeamsViewModel:

class FollowingTeamsViewModel: NSObject, ObservableObject {
    @Published var following_teams = [FollowingTeam]()
    
    init() {
        super.init()
        let defaults = UserDefaults.standard
        let key = defaults.string(forKey: "key") ?? ""
        fetchFollowingTeams(key: key)
    }
    
    // 原fetchFollowingTeams方法不变
}

然后在Home视图中初始化ViewModel:

@StateObject var followingTeamsModel = FollowingTeamsViewModel()

这样数据可能在视图渲染前就加载完成,避免布局变化。

最优方案

优先结合方法一+方法二,既预留了布局空间防止突然挤压,又控制了动画范围,能彻底解决抖动问题。


内容的提问来源于stack exchange,提问作者Mxyb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:07:02