LazyHStack cuts off content when scrolling - ios

I have a LazyHStack nested in a ScrollView for showing some data from an API, but everytime I scroll it, the content is being cut off like this:
Here is the full struct:
struct MovieDetailView: View {
#EnvironmentObject private var navStack: NavigationStack
#ObservedObject var viewModel: MovieDetailVM
init(viewModel: MovieDetailVM) {
self.viewModel = viewModel
//UIScrollView.appearance().bounces = false
}
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .top) {
ScrollView(showsIndicators: false) {
VStack {
GeometryReader { (proxy: GeometryProxy) in
if proxy.frame(in: .global).minY <= 0 {
Image(uiImage: (UIImage(data: viewModel.backdropData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_BACKDROP))!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: proxy.size.width, height: 330)
} else {
Image(uiImage: (UIImage(data: viewModel.backdropData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_BACKDROP))!)
.resizable()
.aspectRatio(contentMode: .fill)
.offset(y: -proxy.frame(in: .global).minY)
.frame(width: proxy.size.width, height: 330 + proxy.frame(in: .global).minY)
}
}
VStack(alignment: .leading) {
FDDivider(height: 20)
HStack {
Image(uiImage: (UIImage(data: viewModel.posterData) ?? UIImage(named: JWConfig.IMG_PLACEHOLDER_MOVIE_POSTER))!)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 120, height: 180)
.cornerRadius(20)
.clipped()
VStack(alignment: .leading) {
Text(viewModel.title)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 25).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top, .bottom], 12)
.lineLimit(3)
HStack {
ForEach(viewModel.genres.prefix(2), id: \.ID) { genre in
JWBorderPill(text: genre.name, textSize: 12, textColor: .SAPPHIRE, borderColor: .DANUBE)
}
}
}.padding([.leading], 10)
Spacer()
}.padding([.leading, .trailing], 20)
FDDivider(height: 20)
HStack(spacing: 50) {
VStack {
Text("Release Date")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text(viewModel.releaseDate)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
VStack() {
Text("Duration")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text("\(viewModel.runtime)")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
VStack() {
Text("Rating")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 15))
.foregroundColor(.gray)
.padding([.bottom], 1)
Text("\(String(format: "%.1f", viewModel.voteAverage)) / 10")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 18).weight(.semibold))
}
}.frame(width: geometry.size.width)
VStack(alignment: .leading) {
Text("Overview")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 23).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top, .bottom], 8)
Text(viewModel.overview)
.font(Font.custom(JWConfig.FONT_ARIAL, size: 17))
.foregroundColor(.gray)
}.padding([.leading, .trailing], 24)
VStack(alignment: .leading) {
Text("Production Companies")
.font(Font.custom(JWConfig.FONT_ARIAL, size: 23).weight(.semibold))
.foregroundColor(.SAPPHIRE)
.padding([.top], 8)
ScrollView(.horizontal, showsIndicators: false) {
LazyHStack {
ForEach(viewModel.productionCompanies, id: \.ID) { company in
ProductionCompanyCell(viewModel: ProductionCompanyCellVM(company))
}
}
}
}.frame(height: 250)
.padding([.leading], 24)
FDDivider(height: 400)
}.frame(width: geometry.size.width)
.background(Color.white)
.cornerRadiusWithEachCorner(50, corners: [.topLeft, .topRight])
.offset(y: 180)
}
}
HStack {
JWBackButton()
Spacer()
}.padding(EdgeInsets(top: 50, leading: 25, bottom: 0, trailing: 0))
}
}.edgesIgnoringSafeArea(.all)
}
}
Is there something wrong with my code? Please let me know if you need the full body code, and I'm using Xcode 12.4 at the moment

Related

Reload body items once data from service layer loads in swiftUI

I'm new to the swiftUI, looking for a way to refresh view once service data retrieved. What I want is, once page loads, -or before page loads- I want to call fillUI function so I can retrieve parsed json data from service layer, with that data I want to refresh this code block so my foreach block works with data I have:
VStack(spacing:15 ) {
ScrollView(.horizontal) {
VStack {
ForEach(0..<5) { i in
MeetingCellView(meetingData: meetingListData?.get(at: i) )
.frame(width: 340, height: 150)
.padding(.horizontal)
}.frame(width: 350)
}
}.frame(width: 350)
}
In UIKit, i was able to solve these issues with a way like loading and retrieving all the data first, then showing the view itself with a data. For swiftUI what is the best approach to do that?
Here is the full code of my related view body. I had searched internet but couldn't find the one yet.
import SwiftUI
struct HomeView: View {
#State var username: String = ""
#State var meetingCode: String = ""
#State var data: GetUserDetailModel? = nil
#State var meetingListData: [Datum]? = nil
#State var requestLoaded = false
var body: some View {
ZStack{
VStack {
Image("home.background")
.resizable()
.frame(maxHeight: 338)
Spacer()
ZStack {
VStack {
RoundedRectangle(cornerRadius: 8)
.padding(.top, -20)
.foregroundColor(.white)
}
ScrollView(.vertical, showsIndicators: false)
{
//MARK: - ScrollView Start
VStack {
HStack(spacing: 13.0) {
NavigationLink(destination: CreateMeetingView()) {
ZStack {
RoundedRectangle(cornerRadius: 12)
.foregroundColor(Color(red: 0.935, green: 0.914, blue: 0.957))
VStack(spacing: 18) {
HStack {
Image("icon.camera")
Spacer()
}
HStack {
Text("New Meeting")
.foregroundColor(Color(red: 0.476, green: 0.228, blue: 0.701))
.font(.custom("inter-semibold", size: 15))
Spacer()
}
}.padding(.horizontal, 15)
}.frame(maxWidth: .infinity, idealHeight: 101)
.padding(.leading, 25)
}
NavigationLink(destination: Text("there"))
{
ZStack {
RoundedRectangle(cornerRadius: 12)
.foregroundColor(Color(red: 0.897, green: 0.939, blue: 0.978))
VStack(spacing: 18) {
HStack {
Image("icon.calendar")
Spacer()
}
HStack {
Text("Schedule Now")
.foregroundColor(Color(red: 0.038, green: 0.525, blue: 0.917))
.font(.custom("inter-semibold", size: 15))
Spacer()
}
}.padding(.horizontal, 15)
}.frame(maxWidth: .infinity, idealHeight: 101)
.padding(.trailing, 25)
}
}
}
VStack {
HStack {
Text("Upcoming Meetings")
.font(.custom("inter-semibold", size: 17))
.padding(.leading, 25)
Spacer()
}
ZStack {
VStack(spacing: 30) {
HStack {
Image("upcoming.calendar")
}
HStack {
Text("You do not have a upcoming meeting.")
.font(.custom("inter-regular", size: 15))
.foregroundColor(Color(red: 0.692, green: 0.692, blue: 0.692))
}
}.hidden()
.padding(.vertical, 46)
VStack(spacing:15 ) {
ScrollView(.horizontal) {
VStack {
ForEach(0..<5) { i in
MeetingCellView(meetingData: meetingListData?.get(at: i) )
.frame(width: 340, height: 150)
.padding(.horizontal)
}.frame(width: 350)
}
}.frame(width: 350)
}
}
.padding(.horizontal ,15)
}.padding(.top, 25)
.padding(.bottom, 100)
//MARK: ScrollView End
}
}
}.ignoresSafeArea()
VStack {
HStack {
Image("splash.logo")
.resizable()
.frame(maxWidth: 100, maxHeight: 20)
.padding(.leading, 24)
Spacer()
Image("icon.profile")
.padding(.trailing,25)
}
VStack(spacing: 10.0) {
HStack {
Text("Good Morning,")
.font(.custom("inter-semibold", size: 13))
.foregroundColor(.white)
Spacer()
}
HStack {
Text(username)
.font(.custom("inter-semibold", size: 22))
.foregroundColor(.white)
Spacer()
}
}.padding(.leading, 24)
ZStack {
Color.white
VStack(spacing: 10.0) {
HStack {
Text("Join Meeting")
.font(.custom("inter-semibold", size: 13))
Spacer()
}
HStack {
TextField("Enter meeting code", text: $meetingCode)
.font(.custom("inter-regular", size: 15))
.keyboardType(.numbersAndPunctuation)
}
}.padding(.horizontal, 15)
}
.cornerRadius(6)
.frame(maxWidth: .infinity, maxHeight: 75.0)
.padding(.horizontal, 25.0)
.padding(.top, 30)
Spacer()
}.hiddenNavigationBarStyle()
}
.onAppear(perform: fillUI)
}
func fillUI() {
username = data?.givenName ?? "error"
Network.meetingList {meetings in
//print(meetings)
meetingListData = meetings?.data
requestLoaded = true
}
}
}
struct HomeView_Previews: PreviewProvider {
static var previews: some View {
HomeView()
}
}
We use task(priority:_:) for that, .e.g
List {
ForEach(meetings) { meeting in
MeetingView(meeting: meeting)
}
}
.navigationTitle(loaded ? "Meetings" : "Loading...")
.task {
loaded = false
meetings = await Meeting.fetchAll()
loaded = true
}
Also your body is far too large and you have too many #State. Break it up into subviews and try to only have 1 or 2 #State per View.

Stacking a HStack below a ZStack in SwiftUI

Disclaimer: New to SwiftUI
I know a ZStack() view allows me to overlap views, which is what I want for the heading section of the app.
I set the ZStack() to not take up the entire height and had expected an HStack(), placed after the ZStack() to do just that, appear after. Instead it also overlaps with the ZStack.
I'm sure it's a simple solution to co-exist. Image and code below.
var body: some View {
GeometryReader { geometry in
ZStack(alignment: .topLeading) {
Ellipse()
.fill(self.bgColor)
.frame(width: geometry.size.width * 1.4, height: geometry.size.height * 0.28)
.position(x: geometry.size.width / 2.35, y: geometry.size.height * 0.1)
.shadow(radius: 3)
.edgesIgnoringSafeArea(.all)
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
Text(self.subtitle)
.font(.subheadline)
.fontWeight(.regular)
.foregroundColor(Color.white)
}
.padding(.leading, 25)
.padding(.top, 20)
Spacer()
VStack(alignment: .trailing) {
Image("SettingsIcon")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
}
.padding(.top, 20)
.padding(.trailing, 25)
}
}
.fixedSize(horizontal: false, vertical: true)
HStack(alignment: .top) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
}
}
}
Try the following code using a top VStack and closing the GeometryReader before the last HStack:
var body: some View {
VStack { // <-- here
GeometryReader { geometry in
ZStack(alignment: .topLeading) {
Ellipse()
.fill(self.bgColor)
.frame(width: geometry.size.width * 1.4, height: geometry.size.height * 0.28)
.position(x: geometry.size.width / 2.35, y: geometry.size.height * 0.1)
.shadow(radius: 3)
.edgesIgnoringSafeArea(.all)
HStack(alignment: .top) {
VStack(alignment: .leading) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
Text(self.subtitle)
.font(.subheadline)
.fontWeight(.regular)
.foregroundColor(Color.white)
}
.padding(.leading, 25)
.padding(.top, 20)
Spacer()
VStack(alignment: .trailing) {
Image("SettingsIcon")
.resizable()
.scaledToFit()
.frame(width: 30, height: 30)
}
.padding(.top, 20)
.padding(.trailing, 25)
}
}.fixedSize(horizontal: false, vertical: true)
} // <-- here end GeometryReader
HStack(alignment: .top) {
Text(self.title)
.font(.title)
.fontWeight(.bold)
.foregroundColor(Color.white)
}
} // <-- here end VStack
}

SwiftUI Crash BoxVTable

I am seeing an odd crash with some beta testers on TestFlight. It seems to be at app startup, but prior to the point where we are making any network calls. There does not seem to be a lot on the internet regarding this, and symbolication isn't helping much either. Just curious if anyone has run into this before and what they did about it? I have had it happen on two tester's devices and I have never been able to recreate the issue locally.
For a bit of context, I am creating a list view on my main screen with a LazyVGrid that contains a LazyHGrid inside of it that are both filled using published vars from my viewmodel, though this seems to happen prior to any of those being created.
Thanks for any ideas / help
Edit: Some more details / actual code:
The view with the grids:
import SwiftUI
import Kingfisher
struct FeaturedView: View {
#EnvironmentObject var viewRouter: ViewRouter
#EnvironmentObject var tabRouter : TabRouter
#StateObject var loadingViewModel = LoadingViewModel()
private let imageProcessor = SVGImgProcessor()
private let playerManager = PlayerManager.shared
private var gridItemLayout = [GridItem(.flexible())]
let userDefaults = UserDefaults.standard
var body: some View {
let padding: CGFloat = 20
let paddingHStack: CGFloat = 25
GeometryReader { geometry in
ZStack(alignment: .top){
Color(hex:"#00091C").edgesIgnoringSafeArea(.all)
VStack {
HStack {
HStack {
Text("Hello, \(loadingViewModel.name)")
.frame(alignment: .leading)
.multilineTextAlignment(.center)
.font(Font.custom("poppins-medium", size: 20))
.foregroundColor(Color(hex:"#667C95"))
.padding(.leading, 15)
.padding(.top, 15)
.padding(.bottom, 15)
Image("PremiumStar")
.resizable()
.frame(width: 15.0, height: 15.0)
.opacity(userDefaults.isSubscriber() ? 1 : 0)
}
Spacer()
Button(action: {
print("Settings Clicked")
viewRouter.currentPage = .settingsFlow
}) {
Image("Settings")
.resizable()
.frame(width: 22.0, height: 22.0)
.padding(15)
}
}
ScrollView(showsIndicators: false) {
VStack(spacing: 10) {
LazyVGrid(columns: gridItemLayout, spacing: 17) {
ForEach(loadingViewModel.getCategories()) { category in
Text(category.title)
.foregroundColor(.white)
.font(Font.custom("poppins-bold", size: 30))
ZStack {
KFImage(URL(string: (category.background?.svg!)!))
.resizable()
.setProcessor(imageProcessor)
.frame(width: geometry.size.width - padding, height: 175, alignment: .topLeading)
.aspectRatio(contentMode: .fill)
.clipped()
.cornerRadius(5)
ScrollView(.horizontal, showsIndicators: false) {
LazyHGrid(rows: gridItemLayout, spacing: 20){
ForEach(loadingViewModel.getSoundsForCategory(category: category.key)) { sound in
Button(action: {
playerManager.play(sound: sound)
}) {
VStack {
ZStack{
RoundedRectangle(cornerRadius: 5).frame(width: 90, height: 90)
.foregroundColor(Color.black)
.opacity(0.85)
ZStack(alignment:.bottomTrailing){
KFImage(URL(string: sound.icon.png!)!)
.resizable()
.renderingMode(.template)
.foregroundColor(.white)
.frame(width: 75, height: 75)
.aspectRatio(contentMode: .fill)
.clipped()
Image("LockIcon")
.frame(width: 12, height: 12, alignment: .bottomTrailing)
.aspectRatio(contentMode: .fill)
.clipped()
.hidden(loadingViewModel.isSubscriber || sound.tier != 2)
}
}
Text(sound.name)
.foregroundColor(.white)
.font(Font.custom("poppins-regular", size: 12))
.lineLimit(1)
.frame(minWidth: 0, idealWidth: 90, maxWidth: 100, alignment: .center)
}
}
}
}.padding(.horizontal)
}
.frame(width: geometry.size.width - paddingHStack, height: 175, alignment: .topLeading)
}
Button("Explore All"){
print("Explore All \(category.title) Tapped")
tabRouter.categoryKey = category.key
tabRouter.hasChanged = true
tabRouter.currentTab = 1
}
.font(Font.custom("poppins-bold", size: 15))
.foregroundColor(Color.white)
}
}.padding(.bottom, 120)
}
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
FeaturedView()
}
}
That is loaded by this tab view, which goes between two screens which share the same viewModel / load the same data
// MARK: Tab View
var body: some View {
ZStack{
TabView(selection: $selectedTab){
FeaturedView()
.environmentObject(tabRouter)
.tabItem{
Label("FEATURED", image: "Featured")
}.tag(0)
.overlay(
VStack {
if (showOverlay && !isExpanded){
playView
} else {
EmptyView()
}
}
)
SoundView()
.environmentObject(tabRouter)
.tabItem{
Label("SOUNDS", image: "Sounds")
}.tag(1)
.overlay(
VStack {
if (showOverlay && !isExpanded){
playView
} else {
EmptyView()
}
}
)
}
}
}

SwiftUI issue on iOS 14 with Scrollview HStack content being cut off

I have a list of buttons that display perfectly on iOS 13 using SwiftUI, but on iOS 14 it cuts the content off where the screen ends.
Has anything changed with regards to how HStacks renders what isn't on the screen? I used to scroll and be able to see all the buttons.
I will attach some screenshots and the code.
var body: some View {
VStack(alignment: .leading, spacing: 0){
Text("Select a venue type")
.font(.custom("MavenProBold", size: 16))
.padding(.leading, 16)
.padding(.top, 18)
.foregroundColor(Color.black)
ScrollView(.horizontal, showsIndicators: false) {
HStack(alignment: .center, spacing: 4, content: {
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
Button(action: {
self.selectedButtonIndex = 0
})
{
VStack(alignment: .center, spacing: 0, content: {
ZStack(alignment: .bottomTrailing){
Image(systemName: "star.fill")
.frame(width: circleFrameSize, height: circleFrameSize, alignment: .center)
.font(.title)
.background(Color(hexString: "#1A88FF"))
.foregroundColor(Color.white)
.clipShape(Circle())
}
Text("Things to do")
.padding(.top, 8)
.font(.custom("MavenProBold", size: 12))
.multilineTextAlignment(.center)
.lineLimit(50)
})
.frame(width: 80, height: 80, alignment: .center)
.padding(.all, 10)
.foregroundColor(Color.black)
}
})
.padding(.leading, 8)
.padding(.trailing, 8)
.padding(.bottom, 8)
}
}
}
I also met this problem. It happens when you have a customized clipShape outside of ScrollView. By customized I mean customized Path of the shape.
From my test, when you use builtin shapes, it works fine, for example:
view.clipShape(Circle())
When you use customized shape but with builtin Path, it also works fine, for example:
view.clipShape(CustomShape())
// which CustomShape is something like:
struct CustomShape: Shape {
func path(in rect: CGRect) -> Path {
return Path(roundedRect: rect, cornerSize: CGSize(width: 10, height: 10)
}
}
But when you use a customized Path in your CustomShape, this issue happens:
view.clipShape(CustomShape())
// which CustomShape is something like:
struct CustomShape: Shape {
func path(in rect: CGRect) -> Path {
let path = UIBezierPath(roundedRect: rect,
byRoundingCorners: corners,
cornerRadii: CGSize(width: radius, height: radius))
return Path(path.cgPath)
}
}
I also tried to draw the path manually(use move, addLine, addArc), it doesn't work.
So the workaround is to use builtin Path in your customized Shape. I guess this is a bug of iOS 14, because it works fine on iOS 13.

SwiftUI won't align ZStacks

I'm currently trying to handle SwiftUI by following a tutorial, but somehow I can't solve one issue:
I created another View, namely my HomeView.swift - this file contains the following code:
import SwiftUI
struct Home: View {
var menu = menuData
#State var show = false
var body: some View {
ZStack {
ZStack(alignment: .topLeading) {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(Color("primary"))
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
Spacer()
}
ZStack(alignment: .topTrailing) {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "map.fill")
.foregroundColor(Color("primary"))
}
.padding(.trailing, 20)
.frame(width: 44, height: 44)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
Spacer()
}
MenuView(show: $show)
}
}
}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
struct MenuRow: View {
var text: String?
var image: String?
var body: some View {
HStack {
Image(systemName: image ?? "")
.foregroundColor(Color("third"))
.frame(width: 32, height: 32, alignment: .trailing)
Text(text ?? "")
.font(Font.custom("Helvetica Now Display Bold", size: 15))
.foregroundColor(Color("primary"))
Spacer()
}
}
}
struct Menu: Identifiable {
var id = UUID()
var title: String
var icon: String
}
let menuData = [
Menu(title: "My Account", icon: "person.crop.circle.fill"),
Menu(title: "Reservations", icon: "house.fill"),
Menu(title: "Sign Out", icon: "arrow.uturn.down")
]
struct MenuView: View {
var menu = menuData
#Binding var show: Bool
var body: some View {
VStack(alignment: .leading, spacing: 20) {
ForEach(menu) { item in
MenuRow(text: item.title, image: item.icon)
}
Spacer()
}
.padding(.top, 20)
.padding(30)
.frame(minWidth: 0, maxWidth: .infinity)
.background(Color.white)
.cornerRadius(30)
.padding(.trailing, 60)
.shadow(radius: 20)
.rotation3DEffect(Angle(degrees: show ? 0 : 60), axis: (x: 0, y: 10, z: 0))
.animation(.default)
.offset(x: show ? 0 : -UIScreen.main.bounds.width)
.onTapGesture {
self.show.toggle()
}
}
}
As you can see, right in the beginning, inside of my Home struct, I tried to align two ZStacks - one .topLeading and one .topTrailing. Reading the docs, this should change its position, but somehow it doesn't. Both stack stay centered.
BTW I haven't particularly touched ContenView.swift yet.
Actually, for either inner ZStack, you need to set frames. This can make them reach edges.
ZStack{
ZStack{
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(Color("primary"))
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
Spacer()
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading)
ZStack{
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "map.fill")
.foregroundColor(Color("primary"))
}
.padding(.trailing, 20)
.frame(width: 44, height: 44)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
Spacer()
}.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topTrailing)
MenuView(show: $show)
}
struct Home: View {
var menu = menuData
#State var show = false
var body: some View {
ZStack {
VStack {
HStack {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(Color("primary"))
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
Spacer()
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "map.fill")
.foregroundColor(Color("primary"))
}
.padding(.trailing, 20)
.frame(width: 44, height: 44)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("shadow"), radius: 10, x: 0, y: 10)
}
}
Spacer()
}
MenuView(show: $show)
}
}
}
Is this the layout that you are looking for? With VStack and HStack you can align the views to the top and on both edges

Resources