guitarguy199
guitarguy199

Reputation: 15

Change button/label text using key:value from local JSON - SwiftUI

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

Answers (2)

cadavid
cadavid

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

jnpdx
jnpdx

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

Related Questions