I am trying to modify Stewart Lynch's Rating View to support box a static representation and a "control" to set the rating. To do that, I need some optional properties to address the two different conditions. So
currentRating
is the current rating, to create a view of that number of symbols.
maxRating
is the maximum possible rating &
mutableRating
is the bound current rating, so I can display the cornet value as filled symbols, with the remainder of symbols up to maxRating
unfilled, as well as an unfilled and struck through symbol to set the rating to 0.
Where I am having problems is making that bound parameter also optional. I found this that suggests it should be possible, but that is also rather old. In any case, I have tried various permutations as seen in the commented lines, trying to get Initialization to work, with various different failures.
struct RatingView: View {
var currentRating: Int?
var maxRating: Int?
@Binding var mutableRating: Int?
var width:Int
var color: UIColor
var sfSymbol: String
public init(
currentRating: Int? = nil,
maxRating: Int? = nil,
mutableRating: Binding<Int?>,
// mutableRating: Binding<Int>?,
// mutableRating: (Binding<Int>)?,
width: Int = 20,
color: UIColor = .systemYellow,
sfSymbol: String = "star"
) {
self.currentRating = currentRating
self.maxRating = maxRating
self._mutableRating = mutableRating
// self._mutableRating = mutableRating ?? Binding.constant(nil)
self.width = width
self.color = color
self.sfSymbol = sfSymbol
}
public var body: some View {
Text("")
}
}
#Preview ("mutating") {
struct PreviewWrapper: View {
@State var rating: Int? = 3
var body: some View {
RatingView(
maxRating: 5,
mutableRating: $rating,
width: 30,
color: .red,
sfSymbol: "heart"
)
}
}
return PreviewWrapper()
}
#Preview ("non mutating") {
struct PreviewWrapper: View {
var body: some View {
RatingView(
currentRating: 3,
width: 20,
color: .red,
sfSymbol: "heart"
)
}
}
return PreviewWrapper()
}
So, my first question is, can I still do this in iOS 17 and if so how? And second, I am curious about the details in what is the difference between these three approaches to Init arguments?
mutableRating: Binding<Int?>
mutableRating: Binding<Int>?
mutableRating: (Binding<Int>)?
EDIT: Clarification of failures
When I use
mutableRating: Binding<Int?>
&
self._mutableRating = mutableRating
I get Missing argument for parameter 'mutableRating' in call
in the non mutating
preview. Which I assume means that the parameter is not actually optional, which makes sense given the differences mentioned.
If I change the argument line to
mutableRating: Binding<Int>?
to make the parameter itself optional then I get Cannot assign value of type 'Binding<Int>' to type 'Binding<Int?>' on the initialization line. One of the fix options offered suggests that this might work,
self._mutableRating = mutableRating ?? nilbut that produces
Cannot assign value of type 'Binding?' to type 'Binding<Int?>'` which brings us back around to the change in the argument.
From my perspective, I believe you're looking for:
public init(
...
mutableRating: Binding<Int?> = .constant(nil),
...
) { }
With the code above, both mutating
and non mutating
previews are valid.