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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:05:17