I am trying to populate a series of LazyVGrids with Items using a @SectionedFetchRequest
in SwiftUI
.
I am getting the correct results, but each time value
or tag
changes and composePredicate
runs, there is a flash during which time the results show aa items as if there was no predicate.
and every once in a while, the new predicate in not applied and the grids show all items.
I’ve tried all kinds of combinations of initial
and oldValue
, newValue
in the .onChange
modifiers:
<code> .onChange(of: value, initial: true) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: newValue)
}
}
.onChange(of: tag) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: value)
}
}
</code>
<code> .onChange(of: value, initial: true) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: newValue)
}
}
.onChange(of: tag) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: value)
}
}
</code>
.onChange(of: value, initial: true) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: newValue)
}
}
.onChange(of: tag) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: value)
}
}
What am I missing?
<code>import SwiftUI
struct PickerGrid: View {
@SectionedFetchRequest<Int16, Item>(
sectionIdentifier: .itemGroup,
sortDescriptors: [SortDescriptor(.itemGroup, order: .forward)]
)
private var items: SectionedFetchResults<Int16, Item>
let bin: Bin
@Binding var value: Int
@Binding var tag: ItemTag
@State private var showOnlyFavourites: Bool = true
var body: some View {
VStack {
ScrollView {
ForEach(items) { section in
VStack{
Text(bin.groups[Int(section.id)])
.font(.title2).bold()
.maxWidth()
.padding(.leading)
LazyVGrid(columns: columns, spacing: 1) {
ForEach(section) { item in
Button(action: {
DispatchQueue.main.async {
tag.item = item
items.nsPredicate = composePredicate(bin: bin, value: Int(tag.item.figValue))
}
}) {
ItemCell(item: item, display: .glyph)
.transition(.scale(scale: 0.1777).combined(with: .opacity))
}
.contextMenu {
ItemContextMenu(item: item)
} preview: {
ItemCell(item: item, display: .value)
.frame(width: item.bin == .cannedGoods ? 180 : 90, height: 90)
}
}
}
}
}
.padding(.top, 12)
}
.onChange(of: value, initial: true) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: newValue)
}
}
.onChange(of: tag) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: value)
}
}
.safeAreaInset(edge: .top) {
HStack {
Button(action: {
showOnlyFavourites.toggle()
items.nsPredicate = composePredicate(bin: bin, value: value)
}){
Image(systemName: showOnlyFavourites ? "heart.fill" : "heart")
.padding(.trailing)
}
}
.padding(.top)
.maxWidth(.trailing)
}
}
}
//MARK: Constants
private let columns = [GridItem(.adaptive(minimum: 70), spacing: 1.0)]
private func composePredicate(bin: Bin, value: Int) -> NSPredicate {
print("nCompose predicaten")
let binPredicate = NSPredicate(format: "bin_ = %d", bin.tag)
var valuePredicate = NSPredicate()
if value != 6 {
valuePredicate = NSPredicate(format: "itemValue = %d", value)
} else {
valuePredicate = NSPredicate(format: "itemValue >= %d", value)
}
let noGenericsPredicate: NSPredicate = NSPredicate(format: "itemGroup != %d", 0)
let onlyFavouritesPredicate: NSPredicate = NSPredicate(format: "isFavourite == true")
var subPredicates: [NSPredicate] = []
subPredicates.append(binPredicate)
subPredicates.append(valuePredicate)
subPredicates.append(noGenericsPredicate)
if showOnlyFavourites {
subPredicates.append(onlyFavouritesPredicate)
}
let finalPredicate = NSCompoundPredicate(type: .and, subpredicates: subPredicates)
print(finalPredicate)
return finalPredicate
}
}
</code>
<code>import SwiftUI
struct PickerGrid: View {
@SectionedFetchRequest<Int16, Item>(
sectionIdentifier: .itemGroup,
sortDescriptors: [SortDescriptor(.itemGroup, order: .forward)]
)
private var items: SectionedFetchResults<Int16, Item>
let bin: Bin
@Binding var value: Int
@Binding var tag: ItemTag
@State private var showOnlyFavourites: Bool = true
var body: some View {
VStack {
ScrollView {
ForEach(items) { section in
VStack{
Text(bin.groups[Int(section.id)])
.font(.title2).bold()
.maxWidth()
.padding(.leading)
LazyVGrid(columns: columns, spacing: 1) {
ForEach(section) { item in
Button(action: {
DispatchQueue.main.async {
tag.item = item
items.nsPredicate = composePredicate(bin: bin, value: Int(tag.item.figValue))
}
}) {
ItemCell(item: item, display: .glyph)
.transition(.scale(scale: 0.1777).combined(with: .opacity))
}
.contextMenu {
ItemContextMenu(item: item)
} preview: {
ItemCell(item: item, display: .value)
.frame(width: item.bin == .cannedGoods ? 180 : 90, height: 90)
}
}
}
}
}
.padding(.top, 12)
}
.onChange(of: value, initial: true) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: newValue)
}
}
.onChange(of: tag) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: value)
}
}
.safeAreaInset(edge: .top) {
HStack {
Button(action: {
showOnlyFavourites.toggle()
items.nsPredicate = composePredicate(bin: bin, value: value)
}){
Image(systemName: showOnlyFavourites ? "heart.fill" : "heart")
.padding(.trailing)
}
}
.padding(.top)
.maxWidth(.trailing)
}
}
}
//MARK: Constants
private let columns = [GridItem(.adaptive(minimum: 70), spacing: 1.0)]
private func composePredicate(bin: Bin, value: Int) -> NSPredicate {
print("nCompose predicaten")
let binPredicate = NSPredicate(format: "bin_ = %d", bin.tag)
var valuePredicate = NSPredicate()
if value != 6 {
valuePredicate = NSPredicate(format: "itemValue = %d", value)
} else {
valuePredicate = NSPredicate(format: "itemValue >= %d", value)
}
let noGenericsPredicate: NSPredicate = NSPredicate(format: "itemGroup != %d", 0)
let onlyFavouritesPredicate: NSPredicate = NSPredicate(format: "isFavourite == true")
var subPredicates: [NSPredicate] = []
subPredicates.append(binPredicate)
subPredicates.append(valuePredicate)
subPredicates.append(noGenericsPredicate)
if showOnlyFavourites {
subPredicates.append(onlyFavouritesPredicate)
}
let finalPredicate = NSCompoundPredicate(type: .and, subpredicates: subPredicates)
print(finalPredicate)
return finalPredicate
}
}
</code>
import SwiftUI
struct PickerGrid: View {
@SectionedFetchRequest<Int16, Item>(
sectionIdentifier: .itemGroup,
sortDescriptors: [SortDescriptor(.itemGroup, order: .forward)]
)
private var items: SectionedFetchResults<Int16, Item>
let bin: Bin
@Binding var value: Int
@Binding var tag: ItemTag
@State private var showOnlyFavourites: Bool = true
var body: some View {
VStack {
ScrollView {
ForEach(items) { section in
VStack{
Text(bin.groups[Int(section.id)])
.font(.title2).bold()
.maxWidth()
.padding(.leading)
LazyVGrid(columns: columns, spacing: 1) {
ForEach(section) { item in
Button(action: {
DispatchQueue.main.async {
tag.item = item
items.nsPredicate = composePredicate(bin: bin, value: Int(tag.item.figValue))
}
}) {
ItemCell(item: item, display: .glyph)
.transition(.scale(scale: 0.1777).combined(with: .opacity))
}
.contextMenu {
ItemContextMenu(item: item)
} preview: {
ItemCell(item: item, display: .value)
.frame(width: item.bin == .cannedGoods ? 180 : 90, height: 90)
}
}
}
}
}
.padding(.top, 12)
}
.onChange(of: value, initial: true) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: newValue)
}
}
.onChange(of: tag) {oldValue, newValue in
withAnimation() {
items.nsPredicate = composePredicate(bin: bin, value: value)
}
}
.safeAreaInset(edge: .top) {
HStack {
Button(action: {
showOnlyFavourites.toggle()
items.nsPredicate = composePredicate(bin: bin, value: value)
}){
Image(systemName: showOnlyFavourites ? "heart.fill" : "heart")
.padding(.trailing)
}
}
.padding(.top)
.maxWidth(.trailing)
}
}
}
//MARK: Constants
private let columns = [GridItem(.adaptive(minimum: 70), spacing: 1.0)]
private func composePredicate(bin: Bin, value: Int) -> NSPredicate {
print("nCompose predicaten")
let binPredicate = NSPredicate(format: "bin_ = %d", bin.tag)
var valuePredicate = NSPredicate()
if value != 6 {
valuePredicate = NSPredicate(format: "itemValue = %d", value)
} else {
valuePredicate = NSPredicate(format: "itemValue >= %d", value)
}
let noGenericsPredicate: NSPredicate = NSPredicate(format: "itemGroup != %d", 0)
let onlyFavouritesPredicate: NSPredicate = NSPredicate(format: "isFavourite == true")
var subPredicates: [NSPredicate] = []
subPredicates.append(binPredicate)
subPredicates.append(valuePredicate)
subPredicates.append(noGenericsPredicate)
if showOnlyFavourites {
subPredicates.append(onlyFavouritesPredicate)
}
let finalPredicate = NSCompoundPredicate(type: .and, subpredicates: subPredicates)
print(finalPredicate)
return finalPredicate
}
}