Reputation: 33
So I've been going through a SwiftUI instagram tutorial and learnt how to load images uploaded by user to firebase in the standard 3x3 instagram view but am now wanting to expand my knowledge and practice doing it in horizontal scrollview.
Here's what I have to create grid view:
import SwiftUI
import URLImage
import FirebaseAuth
struct Photo: Identifiable {
let id = UUID()
var photo = ""
}
struct PhotoView: View {
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
@EnvironmentObject var session: SessionStore
@ObservedObject var profileViewModel = ProfileViewModel()
var body: some View {
return
ScrollView {
if !profileViewModel.isLoading {
VStack(alignment: .leading, spacing: 1) {
// rows
ForEach(0..<self.profileViewModel.splitted.count) { index in
HStack(spacing: 1) {
// Columns
ForEach(self.profileViewModel.splitted[index], id: \.postId) { post in
URLImage(URL(string: post.mediaUrl)!,
content: {
$0.image
.resizable()
.aspectRatio(contentMode: .fill)
}).frame(width: UIScreen.main.bounds.width / 3, height: UIScreen.main.bounds.width / 3).clipped().cornerRadius(5)
}
}
}
}.frame(width: UIScreen.main.bounds.width, alignment: .leading).padding(.top, 2)
}
}.navigationBarTitle(Text("Photos"), displayMode: .inline).navigationBarBackButtonHidden(true).navigationBarItems(leading: Button(action : {
self.mode.wrappedValue.dismiss()
}) {
Image(systemName: "arrow.left")
}).onAppear {
self.profileViewModel.loadUserPosts(userId: Auth.auth().currentUser!.uid)
}
}
}
extension Array {
func splitted(into size:Int) -> [[Element]] {
var splittedArray = [[Element]]()
if self.count >= size {
for index in 0...self.count {
if index % size == 0 && index != 0 {
splittedArray.append(Array(self[(index - size)..<index]))
} else if (index == self.count) {
splittedArray.append(Array(self[index - 1..<index]))
}
}
} else {
splittedArray.append(Array(self[0..<self.count]))
}
return splittedArray
}
}
class ProfileViewModel: ObservableObject {
@Published var posts: [Post] = []
@Published var isLoading = false
var splitted: [[Post]] = []
func loadUserPosts(userId: String) {
isLoading = true
Api.User.loadPosts(userId: userId) { (posts) in
self.isLoading = false
self.posts = posts
self.splitted = self.posts.splitted(into: 3)
}
}
}
And this is what it looks like:
This is the sample code for what I am trying to achieve:
import SwiftUI
import URLImage
import FirebaseAuth
struct TestView: View {
@Environment(\.presentationMode) var mode: Binding<PresentationMode>
var body: some View {
VStack {
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 2) {
ForEach(1..<5) { _ in
Image("photo3").resizable()
.clipShape(Rectangle())
.aspectRatio(contentMode: ContentMode.fill)
.frame(width: 100, height: 100).cornerRadius(10).opacity(1).shadow(radius: 4)
}
}
}.navigationBarTitle(Text("Photos"), displayMode: .inline).navigationBarBackButtonHidden(true).navigationBarItems(leading: Button(action : {
self.mode.wrappedValue.dismiss()
}) {
Image(systemName: "arrow.left")
})
Spacer()
}.padding()
}
}
and here is the sample image of what I want it to look like:
I'm really struggling to understand the ForLoop part and how I can retrieve the image to just be in a simple scrollView.
Any help would be much appreciated!
Thanks!
Upvotes: 1
Views: 974
Reputation: 8547
vacawama has already posted the perfect solution to make it look like your example.
Just to add why you achieve the result, you are getting.
The difference between your code and the sample code is that you are using two ForEach, one for the rows and one for the columns. The array gets splitted with your extension, so you get rows and columns.
//Rows
ForEach(0..<self.profileViewModel.splitted.count) { index in
HStack(spacing: 1) {
// Columns
ForEach(self.profileViewModel.splitted[index], id: \.postId) { post in
Your comments already stating how it works. If you want to have all your images in a horizontal scroller, you just need one ForEach which outputs all your images in a ScrollView.
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 2) {
ForEach(self.profileViewModel.posts, id: \.postId) { post in
Upvotes: 0
Reputation: 154711
You want to loop over the posts in your model. Borrowing from your earlier code, you need something like this:
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 2) {
ForEach(self.profileViewModel.posts, id: \.postId) { post in
URLImage(URL(string: post.mediaUrl)!,
content: {
$0.image
.resizable()
.aspectRatio(contentMode: .fill)
}
)
.frame(width: 100, height: 100)
.clipped()
.cornerRadius(10)
.shadow(radius: 4)
}
}
}
Upvotes: 2