ufookoro
ufookoro

Reputation: 373

SwiftUI Reload View

I have a struct which shuffles and Lists records from CoreData. I would like to reload / Refresh the List view with a Button. I tried to use a function from within the Button. Is there a way I can do this?

var body: some View {
    VStack {
        List {
            ForEach(dictionary.shuffled().prefix(upTo: 10),id: \.self) { word in
                HStack {
                    Text("\(word.englishWord)")
                        .foregroundColor(Color.blue)
                    Text("| \(word.urhoboWord) |")
                        .foregroundColor(Color.green)
                    Image(word.imageName)
                        .resizable()
                        .frame(width:40, height: 40)
                }//HStack
            }//End of ForEach
        }//End of List

        //Button to reload and shuffle list
        Button(action: {}) {
            Text("Shuffle")
                .padding()
                .background(Color.black)
                .foregroundColor(Color.white)
                .cornerRadius(6)
            }
        .navigationBarTitle(Text("Begin Learning"),displayMode: .inline)

Upvotes: 18

Views: 78705

Answers (4)

Quang Hà
Quang Hà

Reputation: 4746

You should move this dictionary.shuffled().prefix(upTo: 10) to your ViewModel and your view just reload base on the data. Take a look at this code for reference:

struct SampleShuffleView : View {
    @ObservedObject var viewModel: ShuffleViewModel
    
    var body : some View {
        VStack {
            List(self.viewModel.listData, id: \.self) { str in
                Text(str)
            }
            
            Button(action: self.shuffle) {
                Text("Shuffle me").padding()
            }.background(Color.white).padding()
            
        }
    }
    
    func shuffle() {
        self.viewModel.shuffle()
    }
}

class ShuffleViewModel : ObservableObject {
    @Published var listData = ["one", "two", "three", "four"]
    
    func shuffle() {
        listData.shuffle()
        //or listData = dictionary.shuffled().prefix(upTo: 10)
    }
}

Note: All view's components will be reloaded when @ObservedObject changes, so consider to separate smaller view-viewmodel(s), or using @State variable.

Hope this helps.

Upvotes: 11

Thyselius
Thyselius

Reputation: 954

This is how I just solved it

1 — Place this in your Extensions.swift (or anywhere, really)

class ReloadViewHelper: ObservableObject {
    func reloadView() {
        objectWillChange.send()
    }
}

2 — Then in the class that didn't update, add this variable.

@ObservedObject var reloadViewHelper = ReloadViewHelper()

3 — Then when You want your whole view to update, just call:

reloadViewHelper.reloadView()

Or like this

Button(action: { reloadViewHelper.reloadView() } ) {
    Text("Update View")
}

Upvotes: 3

Neph Muw
Neph Muw

Reputation: 900

Just trigger any value of the @State or @Published of @ObservableObject. If you do not have such, just create one:

@State var refresh: Bool = false

func update() {
   refresh.toggle()
}

Upvotes: 15

user3441734
user3441734

Reputation: 17534

Think about. To show array and shuffle on tap, do exactly what you would like to see. first show us the array in some "list" like manner and next shuffle it on user action.

struct ContentView: View {
    @State var arr = ["ALFA", "BETA", "GAMA", "DELTA"]
    var body: some View {
        VStack {
        VStack {
            Divider()
            ForEach(arr, id: \.self) { element in
                VStack {
                    Text(element)
                    Divider()
                }
            }
        }
            Spacer()
            Button(action: {
                self.arr.shuffle()
            }) {
                Text("Shuffle")
            }
            Spacer()
        }
    }
}

arr.shuffle() changed the @State of View and force SwiftUI to "reload it" automatically.

Upvotes: 0

Related Questions