The problem, that I am currently facing is related to an electronic program guide screen. I will add a simplified example of what my initial implementation was.
ScrollViewReader {
ScrollView(axis: [.horizontal, .vertical]) {
LazyVStack(pinnedViews: .sectionHeaders) {
Section(header: TimelineView()) {
ForEach(channels) { channel in
LazyHStack(pinnedViews: .sectionHeaders) {
Section(header: ChannelLogoView()) {
ForEach(channel.programs) { program in
ProgramCell(program)
}
}
}
}
}
}
}
The actual implementation included a lot more modifiers and code, but I never got it to work and gave up because most of the problems happening were so weird that there was no code explaining what is going on. Examples are cells appearing out of the view bounds or just disappearing when you scroll around. I thought those are happening because of the nested Lazy stack both with pinned views and I gave up on that approach.
So next I decided to use PreferenceKey for updating the scroll position and offset both the views that need to be pinned based on that. The code looks something like that:
GeometryReader { geoProxy in
ScrollViewReader { scrollProxy in
ScrollView([.vertical, .horizontal], showsIndicators: false) {
ProgramGuideView()
.background(
GeometryReader { geometry in
theme.primaryColor.preference(
key: ScrollOffsetPreferenceKey.self,
value: geometry.frame(in: .named(X)).origin
)
}
)
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { point in
self.position = point //Position is a @State held in the view
}
}
}
}
On top of the grometry reader I have 2 overlays with offsets for the Channel headers and timeline view.
In the program guide view I removed the Lazy stacks and used the normal ones and what was very crucial for this whole combination not to lag was using the drawingGroup()
modifier.
And it worked like a charm when testing on my iPhone 13 mini, but on all other devices that I have tested (14 Pro Max, 14 Pro, 13, Xs) it lags. The only difference that I am seeing is that on those phones when ran from Xcode an error gets logged - Bound preference key tried updating multiple times per frame.
So my questions here are:
- What is the difference between the iPhone 13 mini and the rest of the deices, for this error to occur, and is there a way to overcome it?
- Do you have any suggestions on implementing a view like that using SwiftUI, or just improvement/optimisation ideas on the approaches described above?
I am sorry if I have made any mistakes writing and copy-pasting the code in the snippets above. Also that I am not including the source code directly but I can definitely add more specifics if someone has interest in the problem.
Thanks!