I have sub-navigation inside Listview and trying to achieve leftSlide and rightSlide animation but it always shows default slide animation. I even tried to add .transition(.move(edge: . leading)) & .transition(.move(edge: . trailing))
import SwiftUI
import Combine
struct GameTabView: View {
#State var selectedTab: Int = 0
init() {
UITableView.appearance().sectionHeaderTopPadding = 0
}
var body: some View {
listView
.ignoresSafeArea()
}
var listView: some View {
List {
Group {
Color.gray.frame(height: 400)
sectionView
}
.listRowInsets(EdgeInsets())
}
.listStyle(.plain)
}
var sectionView: some View {
Section {
tabContentView
.transition(.move(edge: . leading)) // NOT WORKING
.background(Color.blue)
} header: {
headerView
}
}
private var headerView: some View {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 16) {
Button {
withAnimation {
selectedTab = 0
}
} label: {
Text("AAAA")
.padding()
}
Button {
withAnimation {
selectedTab = 1
}
} label: {
Text("BBBB")
.padding()
}
Button {
withAnimation {
selectedTab = 2
}
} label: {
Text("BBBB")
.padding()
}
}
}
}
.background(Color.green)
}
#ViewBuilder private var tabContentView: some View {
switch selectedTab {
case 0:
DummyScreen(title: "FIRST", color: .red)
case 1:
DummyScreen(title: "SECOND", color: .green)
case 2:
DummyScreen(title: "THIRD", color: .blue)
default:
EmptyView()
}
}
}
struct DummyScreen: View {
let title: String
let color: Color
var body: some View {
VStack {
ForEach(0..<15, id: \.self) { index in
HStack {
Text("#\(index): title \(title)")
.foregroundColor(Color.black)
.font(.system(size: 30))
.padding(.vertical, 20)
Spacer()
}
.background(Color.yellow)
}
}
.background(color)
}
}
Just like Asperi said, you can change to another type of View to make the transition works.
I tried your code, changed List to VStack with ScrollView inside to wrap around the tabContentView, and the result of the UI showed the same except with a proper animation now, and you don't have to manually adjust the height of your contents since HStack height is dynamic based on your Text() growth.
Edited: header fixed, animation fixed
import SwiftUI
import SwiftUITrackableScrollView //Added
import Combine
struct GameTabView: View {
#State private var scrollViewContentOffset = CGFloat(0) //Added
#State var selectedTab: Int = 0
init() {
UITableView.appearance().sectionHeaderTopPadding = 0
}
var body: some View {
listView
.ignoresSafeArea()
}
var listView: some View {
ZStack { //Added
TrackableScrollView(.vertical, showIndicators: true, contentOffset: $scrollViewContentOffset) {
VStack {
Color.gray.frame(height: 400)
sectionView
}
}
if(scrollViewContentOffset > 400) {
VStack {
headerView
Spacer()
}
}
}
}
var sectionView: some View {
Section {
tabContentView
.transition(.scale) // FIXED
.background(Color.blue)
} header: {
headerView
}
}
private var headerView: some View {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 16) {
Button {
withAnimation {
selectedTab = 0
}
} label: {
Text("AAAA")
.padding()
}
Button {
withAnimation {
selectedTab = 1
}
} label: {
Text("BBBB")
.padding()
}
Button {
withAnimation {
selectedTab = 2
}
} label: {
Text("BBBB")
.padding()
}
}
}
}
.background(Color.green)
}
#ViewBuilder private var tabContentView: some View {
switch selectedTab {
case 0:
DummyScreen(title: "FIRST", color: .red)
case 1:
DummyScreen(title: "SECOND", color: .green)
case 2:
DummyScreen(title: "THIRD", color: .blue)
default:
EmptyView()
}
}
}
struct DummyScreen: View {
let title: String
let color: Color
var body: some View {
VStack {
ForEach(0..<15, id: \.self) { index in
HStack {
Text("#\(index): title \(title)")
.foregroundColor(Color.black)
.font(.system(size: 30))
.padding(.vertical, 20)
Spacer()
}
.background(Color.yellow)
}
}
.background(color)
}
}
Thanks to #tail and #Asperi
I finally got the solution via updating ScrollView with ScrollviewProxy:
import SwiftUI
import Combine
struct GameTabView: View {
#State var selectedTab: Int = 0
#State var proxy: ScrollViewProxy?
init() {
UITableView.appearance().sectionHeaderTopPadding = 0
}
var body: some View {
listView
.ignoresSafeArea()
}
var listView: some View {
List {
Group {
Color.gray.frame(height: 400)
sectionView
}
.listRowInsets(EdgeInsets())
}
.listStyle(.plain)
}
var sectionView: some View {
Section {
tabContentView
} header: {
headerView
}
}
private var headerView: some View {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 16) {
Button {
withAnimation {
selectedTab = 0
self.proxy?.scrollTo(0, anchor: .center)
}
} label: {
Text("AAAA")
.padding()
}
Button {
withAnimation {
selectedTab = 1
self.proxy?.scrollTo(1, anchor: .center)
}
} label: {
Text("BBBB")
.padding()
}
Button {
withAnimation {
selectedTab = 2
self.proxy?.scrollTo(2, anchor: .center)
}
} label: {
Text("BBBB")
.padding()
}
}
}
}
.background(Color.green)
}
#ViewBuilder private var tabContentView: some View {
ScrollViewReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack(spacing: 0) {
ForEach(0..<3, id: \.self) { i in
DummyScreen(title: "Name: \(i)", color: .blue)
.frame(idealWidth: UIScreen.main.bounds.width)
.id(i)
}
}
}
.onAppear {
self.proxy = proxy
}
}
}
}
Related
I'm learning SwiftUI over break for fun over youtube, trying to build a fun little app to learn stuff and i'm attempting to make a custom tab bar at the bottom to control views, and have objects (i made a Person object) that i owuld like to be able to access and modify throughout all my views. From what I can tell, I've achieved that, as it runs perfectly well as I expect it to on the Simulator, but when I try to run on my iPhone I get the error "Thread 1: EXC_BAD_ACCESS (code=257, address=0x481bdfee88082008)"
I'm not familiar with reading memory addresses, i'm just trying to screw around with building apps for fun with my downtime
myTestApp.swift
import SwiftUI
#main
struct myTestApp: App {
var testPerson = Person(name: "Stinky", age: 69)
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(testPerson)
}
}
}
ContentView.swift
import SwiftUI
struct ContentView: View {
#State var selectedIndex = 0
let icons = [
"house", "person", "doc", "dice", "gear"
]
let tabNames = [
"Home", "People", "Overview", "Activities", "Settings"
]
var body: some View {
VStack {
ZStack {
switch selectedIndex {
case 0: HomeView()
case 1: PeopleView()
case 2: OverView()
case 3: ActivitiesView()
case 4: SettingsView()
default: HomeView()
}
}
Divider()
.frame(height: 2.0)
HStack {
ForEach(0..<5, id: \.self) { i in
Spacer()
VStack {
Image(systemName: icons[i])
.frame(height: 20.0)
.font(.system(size:23))
.foregroundColor(self.selectedIndex == i ? Color("SelectedColor") : Color("AccentColor"))
Text("\(tabNames[i])")
.font(.system(size:10, weight: .medium, design: .default))
.foregroundColor(self.selectedIndex == i ? Color("SelectedColor") : Color("AccentColor"))
.padding(.top, 1.0)
}
.onTapGesture {
selectedIndex = i
}
.frame(width: 70.0, height: 60.0)
Spacer()
}
}
.frame(height: 41.0)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Views.swift
import SwiftUI
struct HomeView: View {
#EnvironmentObject var testPerson: Person
var body: some View {
NavigationView {
VStack {
ScrollView {
VStack {
Text(testPerson.name + " \(testPerson.age)")
ForEach(0..<5) { i in
Text("The Train Has Arrived!")
.padding(.all, 3.0)
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.cornerRadius(20)
.background(Color.gray)
}
Button(action: {
testPerson.age += 1
}, label: {
Text("Age: \(testPerson.age)")
.font(.system(size: 20))
.foregroundColor(.white)
.frame(maxWidth: .infinity)
})
.frame(maxWidth: .infinity, maxHeight: 50)
.foregroundColor(.blue)
.background(.blue)
.cornerRadius(15)
.padding(.horizontal)
}
.navigationTitle("Age: \(testPerson.age)")
}
}
}
struct PeopleView: View {
#EnvironmentObject var testPerson: Person
#State var newPersonCreation = false
var body: some View {
NavigationView {
VStack {
ZStack {
Spacer().fullScreenCover(isPresented: $newPersonCreation, content: {
Button("ass", action: {
self.newPersonCreation.toggle()
})
})
}
Text("Age: \(testPerson.age)")
}
.navigationTitle("People")
.toolbar {
Button(action: {
self.newPersonCreation.toggle()
}, label: {
Image(systemName: "plus")
.foregroundColor(.white)
})
}
}
}
}
struct OverView: View {
var body: some View {
NavigationView {
VStack {
}
.navigationTitle("Overview")
}
}
}
struct ActivitiesView : View {
var body: some View {
NavigationView {
VStack {
}
.navigationTitle("Activities")
}
}
}
struct SettingsView: View {
var body: some View {
NavigationView {
VStack {
}
.navigationTitle("Settings")
}
}
}
struct Previews_Views_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Person.swift
import SwiftUI
class Person: ObservableObject {
#Published var name = "Anonymous"
#Published var age = 1
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
I'm trying to have multiple expandable views with animation inside a VStack. I have the following code:
struct ContentView: View {
var body: some View {
NavigationView {
ScrollView {
VStack {
ExpandableView(headerTitle: "First")
ExpandableView(headerTitle: "Second")
Spacer()
}
}
}
}
}
And the ExpandableView:
struct ExpandableView: View {
let headerTitle: String
#State private var collapsed: Bool = true
var body: some View {
Button(
action: {
self.collapsed.toggle()
},
label: {
VStack(spacing: 2) {
ZStack {
Rectangle()
.fill(.gray)
VStack {
Text("\(headerTitle) Header")
if !collapsed {
HStack {
Text("Text A")
Text("Text B")
}
}
}
}
.frame(height: collapsed ? 52 : 80)
ZStack(alignment: .top) {
Rectangle()
.fill(.gray)
.frame(height: 204)
VStack {
Text("Content A")
Text("Content B")
Text("Content C")
}
}
.frame(maxHeight: collapsed ? 0 : .none)
.clipped()
}
}
)
.buttonStyle(PlainButtonStyle())
.animation(.easeOut, value: collapsed)
}
}
The result is this:
As you can see if I open the last expandableView is opens correctly. However if I open the first one when the second is closed, it actually opens the second. It only opens correctly the first one if the second is already open. It seems the VStack is not rendering correctly itself. Any ideas why this happening?
Thanks for the help.
I migth be the way the buttons works. Here is a cleaner solution:
struct ExpandableView: View {
let headerTitle: String
#State private var collapsed: Bool = true
var body: some View {
VStack(spacing: 2) {
Button(
action: {
withAnimation(.easeOut){
self.collapsed.toggle()
}
},
label: {
VStack {
Text("\(headerTitle) Header")
if !collapsed {
HStack {
Text("Text A")
Text("Text B")
}
}
}.frame(maxWidth: .infinity)
})
.buttonStyle(.borderedProminent)
.tint(.gray)
if(!self.collapsed) {
VStack {
Divider().background(.black)
Text("Content A")
Text("Content B")
Text("Content C")
}
}
Spacer()
}
.frame(height: collapsed ? 52 : 204)
.frame(maxWidth: .infinity)
.background(.gray)
.padding()
}
}
firstly I am really new to iOS development and Swift (2 weeks coming here from PHP :))
I am trying to build a iOS application that has a side menu. And my intention is when I click on a item in the menu the new view will appear on screen like the 'HomeViewController' and for each consequent item like example1, 2 etc (In place of the menu button, Note I will be adding the top nav bar soon to open the menu)
I am wondering how I can accomplish this feature?
Thanks
ContentView.swift
import SwiftUI
struct MenuItem: Identifiable {
var id = UUID()
let text: String
}
func controllView(clickedview:String) {
print(clickedview)
}
struct MenuContent: View{
let items: [MenuItem] = [
MenuItem(text: "Home"),
MenuItem(text: "Example1"),
MenuItem(text: "Example2"),
MenuItem(text: "Example3")
]
var body: some View {
ZStack {
Color(UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1))
VStack(alignment: .leading, spacing: 0) {
ForEach(items) {items in
HStack {
Text(items.text)
.bold()
.font(.system(size: 20))
.multilineTextAlignment(/*#START_MENU_TOKEN#*/.leading/*#END_MENU_TOKEN#*/)
.foregroundColor(Color.white)
Spacer()
}
.onTapGesture {
controllView(clickedview: items.text)
}
.padding()
Divider()
}
Spacer()
}
.padding(.top, 40)
}
}
}
struct SideMenu: View {
let width: CGFloat
let menuOpen: Bool
let toggleMenu: () -> Void
var body: some View {
ZStack {
//Dimmed backgroud
GeometryReader { _ in
EmptyView()
}
.background(Color.gray.opacity(0.15))
.opacity(self.menuOpen ? 1 : 0)
.animation(Animation.easeIn.delay(0.25))
.onTapGesture {
self.toggleMenu()
}
//Menucontent
HStack {
MenuContent()
.frame(width: width)
.offset(x: menuOpen ? 0 : -width)
.animation(.default)
Spacer()
}
}
}
}
struct ContentView: View {
#State var menuOpen = false
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
if menuOpen {
withAnimation {
print("Left")
menuOpen.toggle()
}
}
}
if $0.translation.width > -100 {
if !menuOpen {
withAnimation {
print("Right")
menuOpen.toggle()
}
}
}
}
ZStack {
if !menuOpen {
Button(action: {
self.menuOpen.toggle()
}, label: {
Text("Open Menu")
.bold()
.foregroundColor(Color.white)
.frame(width: 200, height: 50, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.background(Color(.systemBlue))
})
}
SideMenu(width: UIScreen.main.bounds.width/1.6, menuOpen: menuOpen, toggleMenu: toggleMenu)
}
.edgesIgnoringSafeArea(.all)
.gesture(drag)
}
func toggleMenu(){
menuOpen.toggle()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The on tap command from the above code:
.onTapGesture {
controllView(clickedview: items.text)
}
HomeViewController.swift
import UIKit
import WebKit
class HomeViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://developer.apple.com")!
webView.load(URLRequest(url: url))
}
}
You'll need a couple of ingredients:
A way to store the state of the currently active view
A way to communicate the state between your menu and main content view
For the first one, I made an enum that listed the different types of views (ViewType) and added it to your MenuItem model.
For the second, you can pass state via a #Binding from parent to child views and back up the chain.
struct MenuItem: Identifiable {
var id = UUID()
let text: String
let viewType : ViewType
}
enum ViewType {
case home, example1, example2, example3
}
struct MenuContent: View{
#Binding var activeView : ViewType
let items: [MenuItem] = [
MenuItem(text: "Home", viewType: .home),
MenuItem(text: "Example1", viewType: .example1),
MenuItem(text: "Example2", viewType: .example2),
MenuItem(text: "Example3", viewType: .example3)
]
var body: some View {
ZStack {
Color(UIColor(red: 33/255.0, green: 33/255.0, blue: 33/255.0, alpha: 1))
VStack(alignment: .leading, spacing: 0) {
ForEach(items) { item in
HStack {
Text(item.text)
.bold()
.font(.system(size: 20))
.multilineTextAlignment(.leading)
.foregroundColor(Color.white)
Spacer()
}
.onTapGesture {
activeView = item.viewType
}
.padding()
Divider()
}
Spacer()
}
.padding(.top, 40)
}
}
}
struct SideMenu: View {
let width: CGFloat
let menuOpen: Bool
let toggleMenu: () -> Void
#Binding var activeView : ViewType
var body: some View {
ZStack {
//Dimmed backgroud
GeometryReader { _ in
EmptyView()
}
.background(Color.gray.opacity(0.15))
.opacity(self.menuOpen ? 1 : 0)
.animation(Animation.easeIn.delay(0.25))
.onTapGesture {
self.toggleMenu()
}
//Menucontent
HStack {
MenuContent(activeView: $activeView)
.frame(width: width)
.offset(x: menuOpen ? 0 : -width)
.animation(.default)
Spacer()
}
}
}
}
struct ContentView: View {
#State private var menuOpen = false
#State private var activeView : ViewType = .home
var body: some View {
let drag = DragGesture()
.onEnded {
if $0.translation.width < -100 {
if menuOpen {
withAnimation {
print("Left")
menuOpen.toggle()
}
}
}
if $0.translation.width > -100 {
if !menuOpen {
withAnimation {
print("Right")
menuOpen.toggle()
}
}
}
}
ZStack {
VStack {
if !menuOpen {
Button(action: {
self.menuOpen.toggle()
}, label: {
Text("Open Menu")
.bold()
.foregroundColor(Color.white)
.frame(width: 200, height: 50, alignment: .center)
.background(Color(.systemBlue))
})
}
switch activeView {
case .home:
HomeViewControllerRepresented()
case .example1:
Text("Example1")
case .example2:
Text("Example2")
case .example3:
Text("Example3")
}
}
SideMenu(width: UIScreen.main.bounds.width/1.6,
menuOpen: menuOpen,
toggleMenu: toggleMenu,
activeView: $activeView)
.edgesIgnoringSafeArea(.all)
}
.gesture(drag)
}
func toggleMenu(){
menuOpen.toggle()
}
}
struct HomeViewControllerRepresented : UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> HomeViewController {
HomeViewController()
}
func updateUIViewController(_ uiViewController: HomeViewController, context: Context) {
}
}
I have created a TabBar which is a view at the root of the app.
I'd like to hide the TabBar component when navigating from the closet view to a subview.
The Closet view is a NavigationView containing multiple NavigationLink
Here is the root view of the app:
struct Home: View {
#State var selected = 0
#ObservedObject var viewModel: HomeViewModel
init(viewModel: HomeViewModel) {
self.viewModel = viewModel
}
var body: some View {
ZStack {
if self.selected == 0 {
// viewModel.feedView
Stylist()
}
else if self.selected == 1 {
OutfitView()
}
else if self.selected == 2 {
viewModel.closetView
} else {
Calendar()
}
VStack {
Spacer()
TabBar(selected: self.$selected)
.frame(width: UIScreen.main.bounds.width - 20, alignment: .center)
}
}
}
Here is the TabBar component:
var body : some View{
HStack{
Spacer(minLength: 0)
HStack{
Button(action: {
self.selected = 0
}) {
Image(systemName: "bolt.fill").foregroundColor(self.selected == 0 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
}
Spacer(minLength: 15)
Button(action: {
self.selected = 1
}) {
Image(systemName: "sun.min.fill").foregroundColor(self.selected == 1 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
}
Spacer(minLength: 15)
Button(action: {
self.selected = 2
}) {
Image(systemName: "cube.box.fill").foregroundColor(self.selected == 2 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
}
Spacer(minLength: 15)
Button(action: {
self.selected = 4
}) {
Image(systemName: "calendar").foregroundColor(self.selected == 4 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
}
}.padding(.vertical, 20)
.padding(.horizontal)
.background(Color(UIColor.systemGray5))
.clipShape(Capsule())
.padding(42)
.animation(.interactiveSpring(response: 0.6, dampingFraction: 0.6, blendDuration: 0.6))
}
}
Is there an way to that properly ?
Update:
When I try #Asperi solution I have an error:
Value of type 'some View' has no member 'observingNavigate'
Maybe that could be caused by how I create closetView ?
So here is how I create ClosetView:
HomeViewModel.swift:
class HomeViewModel: ObservableObject {
}
extension HomeViewModel {
var closetView: some View {
return HomeBuilder.makeClosetView()
}
}
HomeBuilder.swift:
enum HomeBuilder {
static func makeClosetView() -> some View {
let viewModel = ClosetViewModel()
return Closet(viewModel: viewModel)
}
}
You need a callback from your Closet view so root view can perform some action. Here is a demo of possible solution.
Let's assume we have the following demo ClosetView
struct ClosetView: View {
var didNavigate: ((Bool) -> Void)?
var body: some View {
NavigationView {
NavigationLink("Link", destination:
Text("Demo")
.onAppear { didNavigate?(true) }
.onDisappear { didNavigate?(false) }
)
}
}
func observingNavigate(callback: #escaping ((Bool) -> Void)) -> some View {
var view = self
view.didNavigate = callback
return view
}
}
then changes in Home will be the following
#State private var showTabbar = true // << state !!
var body: some View {
ZStack {
if self.selected == 0 {
// viewModel.feedView
Stylist()
}
else if self.selected == 1 {
OutfitView()
}
else if self.selected == 2 {
viewModel.closetView
.observingNavigate { self.showTabbar = !$0 } // << here !!
} else {
Calendar()
}
VStack {
Spacer()
if showTabbar { // << here !!
TabBar(selected: self.$selected)
.frame(width: UIScreen.main.bounds.width - 20, alignment: .center)
}
}
}
}
Note: I don't see how you create viewModel.closetView so callback is injected as property, however it can also be injected via constructor arguments, but this does not change idea much.
I am trying to create pagination in SwiftUI with a List but it's not behaving correctly when scrolled and it's size changes.
Here is the code which I am using for it.
class ViewModel: ObservableObject {
#Published var feeds:[String] = []
init() {
for i in 0..<10{
feeds.append("Page \(i)")
}
}
func appentNewData() -> Void{
for i in self.feeds.count..<(self.feeds.count + 10){
feeds.append("New Page \(i)")
}
}
}
struct ContentView: View {
#ObservedObject var viewModel = ViewModel()
#State var isExpanded:Bool = false
var body: some View {
VStack(spacing:0){
Button(action: {
withAnimation {
self.isExpanded.toggle()
}
}) {
Text("Search Bar ( Tap to expand )")
.font(.title)
.foregroundColor(Color.black)
}
.frame(height: self.isExpanded ? 200 : 100)
.frame(maxWidth:.infinity)
.background(Color.red)
GeometryReader { (proxy) in
List{
ForEach(self.viewModel.feeds, id:\.self) { feed in
FeedView(text: feed, size: proxy.size)
.listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0))
.frame(width:proxy.size.width, height: proxy.size.height)
.border(Color.green ,width: 5.0)
.onAppear {
guard let lastItem = self.viewModel.feeds.last else{
return
}
if lastItem == feed{
self.viewModel.appentNewData()
}
}
}
}
.frame(width:proxy.size.width, height: proxy.size.height)
.background(Color.purple)
.onAppear {
UITableViewCell.appearance().selectionStyle = .none
UITableView.appearance().separatorStyle = .none
UITableView.appearance().isPagingEnabled = true
UITableView.appearance().separatorStyle = .none
UITableView.appearance().showsVerticalScrollIndicator = false
}.onDisappear {
UITableView.appearance().isPagingEnabled = false
UITableView.appearance().showsVerticalScrollIndicator = true
}
}
}.clipped()
}
}
struct FeedView:View {
#State var text:String
var size:CGSize
var body: some View{
VStack(spacing: 20.0){
Text(text)
.font(.largeTitle)
HStack{
Text("Width : \(size.width)")
.font(.headline)
Text("Height : \(size.height)")
.font(.headline)
}
}
.frame(maxWidth:.infinity,maxHeight: .infinity,alignment: .center)
}
}
It behaves like this.
Not sure why it is not dividing the row equally since each row has the same width and height.
Here is the quick project if anyone would like to try out.