Zara replica — part 3

LazyVGrid in action & Product Listing screen

import SwiftUIenum Sizes {

static var navBarHeight: CGFloat { 50 }
static var tabBarHeight: CGFloat { UIScreen.main.bounds.width * 0.15 }
static var screenWidth = UIScreen.main.bounds.width
static var screenHeight = UIScreen.main.bounds.height

}
import SwiftUIstruct TabbarView: View {

@Binding var tab: Tab?

var body: some View {
HStack {
Button(action: {
onTabSelected(.search)
}, label: {
Image(systemName: "magnifyingglass")
.thinFont()
.frame(maxWidth: .infinity)
})

Button(action: { onTabSelected(.bookmark) }, label: {
Image(systemName: "bookmark")
.thinFont()
.frame(maxWidth: .infinity)
})

Button(action: { onTabSelected(.menu) }, label: {

Text("MENU").thinFont()
.frame(maxWidth: .infinity)
})

Button(action: { onTabSelected(.profile) }, label: {
Image(systemName: "person")
.thinFont()
.frame(maxWidth: .infinity)
})

Button(action: { onTabSelected(.cart) }, label: {
Image(systemName: "bag")
.thinFont()
.overlay(
Text("9+").font(.system(size: 7, weight: Font.Weight.light, design: Font.Design.default))
.padding(.top, 2)
, alignment: .center)
.frame(maxWidth: .infinity)
})

}
.frame(maxWidth: .infinity, maxHeight: Sizes.tabBarHeight, alignment: .top)
.textColor()
.bgColor()

}
func onTabSelected(_ tab: Tab) {
self.tab = tab
}
}
struct TabbarView_Previews: PreviewProvider {
static var previews: some View {
TabbarView(tab: .constant(.bookmark))
}
}
import SwiftUI
import KingfisherSwiftUI

struct ProductItemView: View {
var product: Product
var showDetail = {}
var bookmark = {}

var body: some View {

VStack {
KFImage(URL(string: product.mainImage)!)
.resizable()
.scaledToFill()
.frame(width: (Sizes.screenWidth / 2 - 25), height: 250)
.clipped()
.onTapGesture(perform: showDetail)

VStack(alignment: .leading) {
Text(product.title)
.lightFont()
.lineLimit(1)
HStack {
Text(product.price)
.lightFont()
Spacer()
Button(action: bookmark, label: {
Image(systemName: "bookmark")
.lightFont()
.textColor()
})
}
}

}.padding(.horizontal)
}
}

struct ProductItemView_Previews: PreviewProvider {
static var previews: some View {
ProductItemView(product: Product.men.first!)
}
}

NavBar View

import SwiftUIstruct NavBarView: View {

var title: String
var onReturn = {}
var onFilter = {}
var body: some View {
HStack {
Button(action: onReturn, label: {
Image(systemName: "arrow.left")
.thinFont()
})

Text(title)
.font(.system(size: 18, weight: Font.Weight.bold, design: Font.Design.default))
.frame(maxWidth: .infinity, alignment: .center)

Button(action: onFilter, label: {
Text("FILTERS")
.lightFont()
})

}.padding(.horizontal)
.padding(.bottom, 10)
.textColor()
.frame(height: Sizes.navBarHeight, alignment: .bottom)
.bgColor()
}
}
struct NavBarView_Previews: PreviewProvider {
static var previews: some View {
NavBarView(title: "NEW IN")
.preferredColorScheme(.light)
}
}

Product Listing Screen

import SwiftUIstruct ProductListingScreen: View {


@Binding var category: Category?
@EnvironmentObject private var store: Store

@State private var selectedProduct: Product?
private let columns = [
GridItem(.adaptive(minimum: 150), spacing: 20)
]
var body: some View {

return ZStack(alignment: .top) {
ScrollView {
createGrid()
}.padding(.top, Sizes.navBarHeight)
.padding(.horizontal, 15)
createNavBar()

}.onAppear(perform: {
setProducts()
}).fullScreenCover(item: $selectedProduct, content: {
ProductDetailScreen(product: $0){
selectedProduct = nil
}
})

}

fileprivate func createGrid() -> LazyVGrid<ForEach<[Product], String, ProductItemView>> {
LazyVGrid(columns: self.columns, alignment: .center, spacing: 40) {
ForEach(store.state.products) { product in
createProductItemView(product) // 7
}
}
}

fileprivate func createNavBar() -> NavBarView {
return NavBarView(title: "NEW IN") {
category = nil
} onFilter: { }
}

fileprivate func setProducts() {
guard let cat = self.category else {
return
}
switch cat {
case .men:
store.dispatch(.addProducts(Product.men))
case .women:
store.dispatch(.addProducts(Product.women))
case .kids:
store.dispatch(.addProducts(Product.kids))
}
}

fileprivate func createProductItemView(_ product: Product) -> ProductItemView {
return ProductItemView(product: product) {
selectedProduct = product
} bookmark: {
store.dispatch(.bookmark(product))
}
}
}struct ProductListingScreen_Previews: PreviewProvider {
static var previews: some View {
ProductListingScreen(category: .constant(Category.kids)).environmentObject(Store())
}
}

ContentView

struct ContentView: View {

@EnvironmentObject private var store: Store
@State private var presentScreen = false
@State private var selectedTab: Tab?
@State private var selectedCategory: Category?

var body: some View {

if store.state.isLoggedIn {
createHomeScreen()
} else {
createLoginScreen()
}
}

fileprivate func createLoginScreen() -> some View {
return LoginScreen {
store.dispatch(.login)
}.transition(.move(edge: .bottom))
.animation(.easeOut)
}

fileprivate func createHomeScreen() -> some View {

return ZStack(alignment: .bottom){
HomeScreen(category: $selectedCategory)
TabbarView(tab: $selectedTab)
}
.fullScreenCover(isPresented: $presentScreen, content: {
if selectedCategory != nil{
ProductListingScreen(category: $selectedCategory)
}
if let tab = selectedTab {
createTabScreen(tab)
}
})
.onChange(of: selectedCategory) { category in
presentScreen.toggle()
}.onChange(of: selectedTab) { _ in
presentScreen.toggle()
}

}

@ViewBuilder
private func createTabScreen(_ tab: Tab) -> some View {
switch tab {
case .bookmark:
Text("Bookmark")
case .cart:
Text("Shopping bar")
case .search:
Text("Search")
case .profile:
Text("Profile")
case .menu:
Text("Menu")
}
}

}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(Store())
}
}

ZaraReplicaApp

private var store = Store()
.environmentObject(store)
import SwiftUI@main
struct ClothingUIApp: App {
@StateObject private var store = Store()

var body: some Scene {
WindowGroup {

ContentView().environmentObject(store)
}
}
}

Conclusion

Building real world apps.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store