SwiftUI 4 - iOS 16:星级评分视图出现异常动画问题
星级评分视图重绘异常的解决方案
问题说明
以下代码实现的星级评分视图,在iOS 16中点击空心星会出现异常重绘动画,iOS 15.5中则存在轻微闪烁现象:
struct ContentView: View { @State var rating: Float = 1.0 var body: some View { HStack(spacing: 4) { ForEach (0 ..< filledStarsCount, id: \.self) { index in Button { rating = Float(index + 1) } label: { Image(systemName: "star.fill") } } ForEach (0 ..< emptyStarsCount, id: \.self) { index in Button { rating = Float(index + filledStarsCount + 1) } label: { Image(systemName: "star") } } } .font(.title) } var emptyStarsCount: Int { filledStarsCount == 5 ? 0 : abs(5 - filledStarsCount ) } var filledStarsCount: Int { let rounded = Int(rating) if rounded > 5 { return 5 } else { return rounded } } }

问题根源
原代码通过两个动态ForEach分别渲染填充和空心星星,每次评分变化时,两个ForEach的元素数量会改变,SwiftUI会销毁旧视图并创建新视图,进而触发不必要的重绘动画或闪烁。
修复代码
改为固定渲染5个星星,通过当前索引与评分的关系控制星星的填充状态,避免视图的销毁重建:
struct ContentView: View { @State var rating: Float = 1.0 var body: some View { HStack(spacing: 4) { ForEach(1...5, id: \.self) { starIndex in Button { rating = Float(starIndex) } label: { Image(systemName: starIndex <= Int(rating) ? "star.fill" : "star") } } } .font(.title) } }
效果说明
这种实现方式下,所有星星视图始终存在,仅切换图片资源来更新状态,SwiftUI只会更新图片内容,不会触发视图重建,彻底解决重绘动画和闪烁问题,同时代码更简洁易维护。
内容的提问来源于stack exchange,提问作者JAHelia
相关产品推荐
相关产品推荐

