I'm trying to build simple app with Staggered Grid View in Swift UI ( like in Image )
I but with my implementation Grid Items are getting overlapped.
How can i resolve this issue?
Code :
StaggeredGrid:
struct StaggeredGrid<Content: View,T:Identifiable>: View where T: Hashable{
// MARK: - Properties
var content: (T) -> Content
var list: [T]
var columns: Int
var showIndicators:Bool
var spacing: CGFloat
var columnsArray: [GridItem] = []
init(list: [T], columns: Int, showIndicators: Bool = false, spacing: CGFloat = 10,@ViewBuilder content: @escaping (T) -> Content) {
self.content = content
self.list = list
self.columns = columns
self.showIndicators = showIndicators
self.spacing = spacing
self.columnsArray = Array(repeating: GridItem(.flexible(),spacing: spacing), count: columns)
}
func setUpList() -> [[T]]{
var gridArray: [[T]] = Array(repeating: [], count: columns)
var currentIndex:Int = 0
for object in list{
gridArray[currentIndex].append(object)
if currentIndex == (columns - 1){
currentIndex = 0
}else{
currentIndex += 1
}
}
return gridArray
}
// MARK: - Body
var body: some View {
ScrollView(.vertical,showsIndicators: showIndicators){
LazyVGrid(columns: columnsArray, spacing: spacing) {
ForEach(list,id: \.self){ columnData in
content(columnData)
}
}.padding()
}
}
}
Home Screen :
struct HomeScreen: View {
@StateObject var vm = HomeScreenVM()
@Namespace var animation
var body: some View {
NavigationView {
VStack {
StaggeredGrid(list: vm.arrayPhotos, columns: vm.column, content: { photo in
PhotoGridItem(photo: photo)
})
.padding(.horizontal)
.navigationTitle("Photos")
.searchable(text: $vm.searchText, prompt: "Search photos by title,tags")
.onChange(of: vm.searchText, perform: { newValue in
vm.loadData()
})
.onSubmit(of: .search, vm.loadData)
switch vm.viewState {
case .loading:
ProgressView()
case .error(let errorMsg):
VStack {
Text(errorMsg)
Button(
"Retry",
action: {
vm.loadData()
}
)
}
case .dataLoaded:
Text("")
}
}
}.onAppear(perform: vm.onAppear)
}
}
Grid Item :
struct PhotoGridItem: View {
var photo: Photo
var body: some View {
GeometryReader { reader in
VStack(spacing: 10) {
AsyncImage(url: URL(string: photo.imagePath)) { image in
image
.resizable()
.scaledToFill()
} placeholder: {
Color.gray.opacity(0.1)
}
Text(photo.title)
.font(.headline)
.frame(height: 80)
}.cornerRadius(10)
.clipped()
.background(Color.white)
.shadow(radius: 3)
}
.frame(height: CGFloat.random(in: 130...170), alignment: .top)
}
}

