Hi everyone,
I'm having a hard time figuring out why the code below results in weird behaviour with the ScrollView.
Code :
struct MainView: View {
@State var strings: [String] = ["A", "B", "C", "D", "E"]
@State var ints: [Int] = Array(1...300)
@State var selectedInt: Int?
var body: some View {
ZStack {
ScrollView {
VStack {
ForEach(strings, id: \.self) { string in
VStack {
HStack {
Text(string)
Spacer()
}
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(ints, id: \.self) { int in
VStack {
Text(String(int))
Spacer()
}
.frame(minWidth: 0, maxWidth: .infinity)
.frame(height: 200)
.background(
RoundedRectangle(cornerRadius: 5)
.fill(int % 2 == 0 ? .orange : .green)
)
.onTapGesture {
self.selectedInt = int
}
}
}
}
}
}
.padding()
}
if let selectedInt {
VStack {
Spacer()
Text(String(selectedInt))
Spacer()
Button {
self.selectedInt = nil
} label: {
Image(systemName: "x.circle")
.resizable()
.scaledToFit()
.frame(width: 30)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
}
}
}
}
Issue: Everything is working fine until I scroll to the 3rd or 4th string (after half the full "list" for example) and use the onTapGesture, then the ScrollView goes crazy and goes up for a reason I don't understand (just at the moment I tap the element).
Do I miss something or is this just a bug ?
Thank you for your help :)
Regards Jim
It seems that zstack still has some issues when recalculating multiple layers with lots of views inside it. I consider that overly a floating view on zstack, this view was not calculated by zstack, I copied the code of floating view from here, and the following is the code modified from your version:
import SwiftUI
struct TMainWnd: View {
@State var strings: [String] = ["A", "B", "C", "D", "E"]
@State var ints: [Int] = Array(1...300)
@State var selectedInt: Int?
@State var isShow = false
var body: some View {
ZStack {
ScrollView {
VStack {
ForEach(strings, id: \.self) { string in
VStack {
HStack {
Text(string)
Spacer()
}
LazyVGrid(columns: [GridItem(.flexible()), GridItem(.flexible()), GridItem(.flexible())]) {
ForEach(ints, id: \.self) { int in
VStack {
Text(String(int))
Spacer()
}
.frame( maxWidth: .infinity )
.frame(height: 200)
.background(
RoundedRectangle(cornerRadius: 5)
.fill(int % 2 == 0 ? .orange : .green)
)
.onTapGesture {
self.selectedInt = int
}
}
}
}
}
}
.padding()
}
}.floatingView(above: TFloatingWnd(selectedInt: $selectedInt))
}
}
struct TFloatingWnd : View
{
@Binding var selectedInt : Int?
var body: some View {
VStack {
Spacer()
if let selectedInt {
Text( String(selectedInt ) )
}
Spacer()
if let selectedInt {
Button {
self.selectedInt = nil
} label: {
Image(systemName: "x.circle")
.resizable()
.scaledToFit()
.frame(width: 30)
}
}
}.frame( maxWidth: .infinity, maxHeight: .infinity)
}
}
extension View {
func floatingView<Content: View>(above: Content) -> ModifiedContent<Self, Above<Content>> {
self.modifier(Above(aboveContent: above))
}
}
struct Above<AboveContent: View>: ViewModifier {
let aboveContent: AboveContent
func body(content: Content) -> some View {
content.overlay(
GeometryReader { proxy in
Rectangle().fill(Color.clear).overlay(
self.aboveContent,
alignment: .center
)
},
alignment: .center
)
}
}