| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- //
- // LNFiveStarScoreView.swift
- // Lanu
- //
- // Created by OneeChan on 2025/11/14.
- //
- import Foundation
- import UIKit
- import SnapKit
- protocol LNFiveStarScoreViewDelegate: NSObject {
- func onFiveStarScoreView(view: LNFiveStarScoreView, scoreChanged newScore: Double)
- }
- class LNFiveStarScoreView: UIView {
- private let stackView = UIStackView()
- private var starViews: [LNStarScoreView] = []
- weak var delegate: LNFiveStarScoreViewDelegate? = nil
-
- var score: Double = 0.0 {
- didSet {
- guard oldValue != score else { return }
- let fixed = score.bounded(min: 0.0, max: 5.0)
- for (index, view) in starViews.enumerated() {
- if fixed - 1 > Double(index) {
- view.score = 1.0
- } else {
- view.score = fixed - Double(index)
- }
- }
- delegate?.onFiveStarScoreView(view: self, scoreChanged: score)
- }
- }
- var icSize: CGFloat? {
- didSet { starViews.forEach { $0.icSize = icSize } }
- }
- var spacing: CGFloat? {
- didSet { stackView.spacing = spacing ?? 0 }
- }
- var startType: LNStarType = .normal {
- didSet { starViews.forEach { $0.curType = startType } }
- }
- var editable: Bool = false
-
- var unit: Double = 1
-
- override init(frame: CGRect) {
- super.init(frame: frame)
-
- setupViews()
- }
-
- required init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
- extension LNFiveStarScoreView {
- @objc
- private func handleTap(_ tap: UITapGestureRecognizer) {
- guard editable else { return }
- let position = tap.location(in: self)
- for (index, view) in starViews.enumerated() {
- if CGRectContainsPoint(view.frame, position) {
- let offset = position.x - view.frame.origin.x
- var newScore = offset / view.frame.width
- newScore = ceil(newScore / unit) * unit
-
- score = newScore + Double(index)
- break
- }
- }
- }
- }
- extension LNFiveStarScoreView {
- private func setupViews() {
- stackView.axis = .horizontal
- stackView.distribution = .equalSpacing
- addSubview(stackView)
- stackView.snp.makeConstraints { make in
- make.edges.equalToSuperview()
- }
-
- for _ in 0..<5 {
- let star = LNStarScoreView()
- stackView.addArrangedSubview(star)
- starViews.append(star)
- }
-
- let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
- addGestureRecognizer(tap)
- }
- }
- #if DEBUG
-
- import SwiftUI
- struct LNFiveStarScoreViewPreview: UIViewRepresentable {
- func makeUIView(context: Context) -> some UIView {
- let container = UIView()
- container.backgroundColor = .lightGray
-
- let view = LNFiveStarScoreView()
- view.startType = .whiteBorder
- view.editable = true
- container.addSubview(view)
- view.snp.makeConstraints { make in
- make.leading.centerY.equalToSuperview()
- make.width.equalTo(300)
- }
- view.score = 1.3
-
- return container
- }
-
- func updateUIView(_ uiView: UIViewType, context: Context) { }
- }
- #Preview(body: {
- LNFiveStarScoreViewPreview()
- })
- #endif
|