SwiftUI实现支持小数填充的星级评分视图(兼容iOS 14)
实现兼容iOS 14的星级部分填充效果
要实现单颗星的部分填充(比如70%),可以通过裁剪填充星图的方式实现,完全兼容iOS 14,无需使用overlay方法。以下是完整的修改方案:
1. 改造星级容器视图(AverageStarsView)
首先需要计算每颗星的填充比例,生成对应进度的星视图:
import SwiftUI struct AverageStarsView: View { @Binding var rating: Double private let maxStars = 5 // 最大支持5颗星 var body: some View { HStack(spacing: 4) { ForEach(0..<maxStars, id: \.self) { index in // 计算当前星的填充进度 let currentStarThreshold = Double(index + 1) let progress: Double if rating >= currentStarThreshold { progress = 1.0 // 完全填充 } else if rating > Double(index) { progress = rating - Double(index) // 部分填充 } else { progress = 0.0 // 空星 } StarView(progress: progress) } } .frame(maxHeight: 16) } } struct AverageStarsView_Previews: PreviewProvider { static var previews: some View { AverageStarsView(rating: .constant(4.7)) } }
2. 改造单星视图(StarView)
通过GeometryReader获取星图尺寸,结合frame和clipped实现部分裁剪填充:
struct StarView: View { private let fillColor = Color.yellow private let emptyColor = Color.gray let progress: Double // 0.0~1.0的填充比例 var body: some View { GeometryReader { geometry in ZStack(alignment: .leading) { // 空星背景层 starImage .foregroundColor(emptyColor) // 填充星层:根据进度裁剪宽度 starImage .foregroundColor(fillColor) .frame(width: geometry.size.width * CGFloat(progress), alignment: .leading) .clipped() } } .aspectRatio(contentMode: .fit) } // 封装星图加载逻辑,添加 fallback 防止图片缺失 private var starImage: Image { if let uiImage = UIImage(named: "icon-star", in: .sharedResources, compatibleWith: nil) { return Image(uiImage: uiImage) .resizable() .renderingMode(.template) } else { return Image(systemName: "star.fill") .resizable() } } } struct StarView_Previews: PreviewProvider { static var previews: some View { HStack(spacing: 4) { StarView(progress: 1.0) StarView(progress: 0.7) StarView(progress: 0.0) } .frame(maxHeight: 16) } }
实现原理
- 进度计算:遍历5颗星,根据当前rating判断每颗星的填充状态:完全填充(rating≥星的序号)、部分填充(rating在当前星序号区间内)、空星(rating<星的起始序号)。
- 部分填充:利用
GeometryReader获取星图的实际宽度,将填充星的宽度设置为总宽度×进度比例,再通过clipped()裁剪超出部分,实现星图的局部填充效果。 - 兼容性:所有API均支持iOS 14及以上,无需依赖高版本的
overlay特性。
内容的提问来源于stack exchange,提问作者Ashan
相关产品推荐
相关产品推荐

