Reputation: 373
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
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
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
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
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