如何不修改RatingView代码在UIKit中获取SwiftUI视图选中评分值
问题
现有如下已实现的SwiftUI评分视图RatingView,要求不改动RatingView任意一行代码,在UIKit视图控制器中获取用户选中的评分值。
原有代码如下:
struct RatingView: View { @Binding var rating: Int? private func starType(index: Int) -> String { if let rating = rating { return index <= rating ? "star.fill" : "star" } else { return "star" } } var body: some View { HStack { ForEach(1...5, id: \.self) { index in Image(systemName: self.starType(index: index)) .foregroundColor(Color.orange) .onTapGesture { rating = index } } } } } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .white // .constant(3) will be replaced by something in the ViewController so it can handle the changes for the rating let hostingController = UIHostingController(rootView: RatingView(rating: .constant(3))) guard let ratingsView = hostingController.view else { return } self.addChild(hostingController) self.view.addSubview(ratingsView) }
解决方案
核心思路是利用SwiftUI Binding的自定义构造能力,不需要修改原RatingView的任何代码,只需要替换原本传入的.constant(3),自己实现一个双向绑定,在绑定值被写入时捕获评分变化即可。
Binding本质是对值的读写闭包封装,原视图内部对rating的赋值操作,最终会触发我们自定义的set逻辑,自然就能把用户选择的评分同步到UIKit侧。
修改后的ViewController实现如下:
class ViewController: UIViewController { // 存储当前选中的评分值,初始值与原代码保持一致为3 private var selectedRating: Int? = 3 override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white // 自定义双向绑定替换原来的.constant(3) let ratingBinding = Binding<Int?>( get: { [weak self] in self?.selectedRating }, set: { [weak self] newValue in self?.selectedRating = newValue // 在此处执行评分变化后的业务逻辑,例如更新UI、上报数据等 print("用户当前选中评分为:\(newValue ?? 0)") } ) let hostingController = UIHostingController(rootView: RatingView(rating: ratingBinding)) guard let ratingsView = hostingController.view else { return } addChild(hostingController) view.addSubview(ratingsView) // 补充布局约束,避免视图位置异常 ratingsView.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ ratingsView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 40), ratingsView.centerXAnchor.constraint(equalTo: view.centerXAnchor) ]) } }
实现说明:
- 全程没有修改
RatingView的任何代码,完全符合题目限制要求 - 自定义
Binding的get闭包负责把UIKit侧存储的评分值回传给SwiftUI视图,保证星星填充状态和选中值一致 set闭包会在用户点击星星触发rating = index赋值时自动调用,在这里即可拿到最新的评分值,执行任意UIKit侧的业务逻辑- 补充了必要的自动布局约束,将评分视图固定在安全区顶部居中位置,避免视图偏移
更新说明:题目原始代码来自社区公开讨论内容,本次实现未对原始
RatingView代码做任何修改。
内容的提问来源于stack exchange,提问作者Mary Doe
相关产品推荐
相关产品推荐

