0

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)
    }
}

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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()
            }
        }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.