Reputation: 15
New to SwiftUI. Trying to get a JSON key:value array to update to the next random item when the user presses the button. Got it to load up just fine, but the button does nothing. Tried making a shuffle function, but couldn't find a way to pass in the new values to the Text areas. Also tried to make my decodedQuotes and quote variables into @State vars inside the View, but they initialize before self is available.
Could normally call touchesBegan and write a simple function in Storyboard. Is there something similar I could do here?
var decodedQuotes = Bundle.main.decode([Quote].self, from: "quotes.json")
// parses an array with "quote":"name" pairs
var quote = decodedQuotes.randomElement()!
struct QuoteView: View {
var body: some View {
Button(action:
// Need it to update the Text below with a new random item from quote
)
HStack {
VStack {
HStack(alignment: .center) {
Text(quote.quote)
.multilineTextAlignment(.center)
.padding()
.foregroundColor(.black)
}
HStack {
Text("-\(quote.name)")
.foregroundColor(.black)
}
}
}
.frame(width: 300, height: 300, alignment: .center)
.background(Background(isHighlighted: true, shape: Rectangle()))
.foregroundColor(.blue)
.padding(4)
.cornerRadius(20)
}
}
Upvotes: 0
Views: 195
Reputation: 9
I believe this is a better implementation in the current SwiftUI where the text actually changes within the button. I hope it helps>
import SwiftUI
struct Quote {
var quote : String
var name : String
}
var decodedQuotes = [Quote(quote: "Title 1", name: "Description 1."),
Quote(quote: "Title 2", name: "Second description."),
Quote(quote: "Title 3", name: "final item."),]
struct ContentView: View {
@State var quote : Quote? = decodedQuotes.randomElement()
var body: some View {
Button(action: {
quote = decodedQuotes.randomElement()
}) {
Text("New quote")
if let quote = quote {
HStack {
VStack {
VStack(alignment: .center) {
Text(quote.quote)
.multilineTextAlignment(.center)
.padding()
.foregroundColor(.blue)
Text("-\(quote.name)")
.foregroundColor(.blue)
}
}
}
.frame(width: 300, height: 300, alignment: .center)
.foregroundColor(.blue)
.padding(4)
.cornerRadius(20)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Upvotes: 0
Reputation: 52416
You were on the right track with @State
struct Quote {
var quote : String
var name : String
}
var decodedQuotes = [Quote(quote: "test1", name: "name1"),
Quote(quote: "test2", name: "name2"),
Quote(quote: "test3", name: "name3"),]
struct QuoteView: View {
@State var quote : Quote? = decodedQuotes.randomElement()
var body: some View {
Button(action: {
quote = decodedQuotes.randomElement()
}) {
Text("New quote")
}
if let quote = quote {
HStack {
VStack {
HStack(alignment: .center) {
Text(quote.name)
.multilineTextAlignment(.center)
.padding()
.foregroundColor(.black)
}
HStack {
Text("-\(quote.name)")
.foregroundColor(.black)
}
}
}
.frame(width: 300, height: 300, alignment: .center)
.foregroundColor(.blue)
.padding(4)
.cornerRadius(20)
}
}
}
Obviously, for testing, I just used an array of pre-made Quotes
If you wanted to, you could make decodedQuotes
a @State
property on the QuoteView
as well and decode them in onAppear
I've also chosen to make quote
an optional for now. I check to see if it's available by doing the if let quote = quote
line. This should be a bit future-proof in case you start loading quotes from other places at some point.
Upvotes: 1