Using the SwiftUI framework, I created this reusable View (minus styling bells and whistles):
struct RatingView: View {
let criteria: String
@State var rating: Int
var body: some View {
HStack {
Button {
if rating > 0 {
rating -= 1
}
} label: {
Image(systemName: "heart.slash.fill")
}
Spacer()
Text("\(criteria): \(rating)")
Spacer()
Button {
if rating < 1 {
rating += 1
}
} label: {
Image(systemName: "heart.fill")
}
}
}
}
And implemented it here (again, without the styling bells and whistles):
struct ScoringView: View {
let story = "Story"
let cheese = "Cheese"
let love = "Romance"
let actor = "In character"
var storyRating = 0
var cheesyRating = 0
var loveRating = 0
var actorRating = 0
var roundScore: Int {
storyRating + cheesyRating + loveRating + actorRating
}
var body: some View {
VStack {
RatingView(criteria: story, rating: storyRating)
RatingView(criteria: cheese, rating: cheesyRating)
RatingView(criteria: love, rating: loveRating)
RatingView(criteria: actor, rating: actorRating)
}
Spacer()
VStack {
Text("Score this round:")
Text("\(roundScore)")
}
}
}
No matter the changes I make to the rating buttons, the roundScore
computed property does not change and remains at zero.
I tested the computed property in a Playground, and it works! But since I wasn't able to find anything on SO about the combo of computed properties and reusable views, so I wonder if the reusable view is messing with me.
Any thoughts?
You need something yo trigger View
updates or SwiftUI doesn't know when to redraw.
Add @State
@State var storyRating = 0
@State var cheesyRating = 0
@State var loveRating = 0
@State var actorRating = 0
and remove it from RatingView
@Binding var rating: Int
@State
is a source of truth and @Binding
is a two-way connection.
You will also have to add $
when initializing views
RatingView(criteria: story, rating: $storyRating)
RatingView(criteria: cheese, rating: $cheesyRating)
RatingView(criteria: love, rating: $loveRating)
RatingView(criteria: actor, rating: $actorRating)