How can i remove this space from a SwiftUI custom CustomTabBar - swift

You can see the issue in the image below there is a space above the Rectangle with a teal Color that I cant remove so that code can match the design.
You can replicate the issue using the code below:
import SwiftUI
#main
struct DatemeApp: App {
var body: some Scene {
WindowGroup {
RootView()
}
}
}
and
import SwiftUI
struct RootView: View {
#StateObject var viewRouter = ViewRouter()
var body: some View {
CustomTabBar(viewRouter: viewRouter)
}
}
struct RootView_Previews: PreviewProvider {
static var previews: some View {
RootView()
}
}
struct HomeView: View {
var body: some View {
ScrollView(.vertical) {
SectionView()
SectionView()
SectionView()
SectionView()
SectionView()
}
}
}
struct SectionView: View {
var body: some View {
VStack {
ScrollView(.horizontal) {
LazyHStack( pinnedViews: .sectionHeaders) {
ForEach(0..<8) { _ in
Rectangle()
.foregroundColor(.gray)
.frame(width: 132, height: 168)
}
}
}
}.background(Color.green)
}
}
class ViewRouter: ObservableObject {
#Published var currentPage: Page = .home
}
enum Page {
case home
case liked
case records
case user
}
struct CustomTabBar: View {
#StateObject var viewRouter: ViewRouter
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
switch viewRouter.currentPage {
case .home:
HomeView()
.background(Color.green)
case .liked:
Text("Msg")
case .records:
Text("Cal")
case .user:
Text("People")
}
Spacer()
Rectangle()
.fill(Color.teal)
.frame(height: 2)
ZStack {
HStack {
TabBarIcon(viewRouter: viewRouter, assignedPage: .home, width: geometry.size.width/5, height: geometry.size.height/28, systemIconName: "house.fill", tabName: "Home")
TabBarIcon(viewRouter: viewRouter, assignedPage: .liked, width: geometry.size.width/5, height: geometry.size.height/28, systemIconName: "ellipsis.message.fill", tabName: "Msg")
Image(systemName: "plus.circle.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.symbolRenderingMode(.palette)
.foregroundStyle(Color.yellow, Color.teal)
.offset(y: -geometry.size.height / 13.5)
.onTapGesture {
print("Plus Button Tapped")
}
TabBarIcon(viewRouter: viewRouter, assignedPage: .records, width: geometry.size.width/5, height: geometry.size.height/28, systemIconName: "calendar", tabName: "Cal")
TabBarIcon(viewRouter: viewRouter, assignedPage: .user, width: geometry.size.width/5, height: geometry.size.height/28, systemIconName: "person", tabName: "People")
}
.frame(width: geometry.size.width, height: geometry.size.height/8)
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
}
struct TabBarIcon: View {
#StateObject var viewRouter: ViewRouter
let assignedPage: Page
let width, height: CGFloat
let systemIconName, tabName: String
var body: some View {
VStack {
Image(systemName: systemIconName)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: width, height: height)
// .padding(.top, 10)
Text(tabName)
.font(.footnote)
Spacer()
}
.padding(.horizontal, -4)
.onTapGesture {
viewRouter.currentPage = assignedPage
}
.foregroundColor(viewRouter.currentPage == assignedPage ? Color(UIColor(hue:0.713, saturation:0.532, brightness:0.393, alpha:1.000)) : Color(UIColor(hue:0.648, saturation:0.421, brightness:0.705, alpha:1.000)))
}
}

You have 2 elemnts in your CustomTabBars VStack that cause this. Remove:
Spacer()
Rectangle()
.fill(Color.teal)
.frame(height: 2)
A spacer has a minimum height, also the Rectange has an explicit height of 2.

Related

Why does my custom tab bar get pushed up everytime the on screen keyboard pops up?

I've made a custom tab bar and I'm trying to add a search bar on one of my views. For some reason half of the tab gets pushed up when the onscreen keyboard appears. Ive tried " .ignoresSafeArea(.keyboard)" literally everywhere and the only thing that happens is my icons for the tab disappear but the top of the tab still stays there. I've been trying to fix it for the last 24 hours but I'm getting nowhere, can somebody please help me with this. Thanks!
Code for Custom Tab Bar:
import SwiftUI
enum Tabs: Int {
case home = 0
case hot = 1
case favourites = 2
case settings = 3
}
struct TabBar: View {
#Binding var selectedTab : Tabs
var body: some View {
HStack (alignment: .center){
Button {
//switch to home
selectedTab = .home
} label: {
GeometryReader { geo in
if selectedTab == .home {
Rectangle()
// .ignoresSafeArea(.keyboard)
.foregroundColor(.red)
.frame(width: geo.size.width/2, height: 5)
.padding(.leading, geo.size.width/4)
}
VStack (alignment: .center){
Image(systemName: "house")
// .ignoresSafeArea(.keyboard)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.padding(.top, 40.0)
}
// .ignoresSafeArea(.keyboard)
.frame(width: geo.size.width, height: geo.size.height)
}
//.ignoresSafeArea(.keyboard)
.offset(y: -35)
//.ignoresSafeArea(.keyboard)
}
// .ignoresSafeArea(.keyboard)
.tint(Color.black)
Button {
//Switch views
selectedTab = .hot
} label: {
GeometryReader { geo in
if selectedTab == .hot {
Rectangle()
//.ignoresSafeArea(.keyboard)
.foregroundColor(.red)
.frame(width: geo.size.width/2, height: 5)
.padding(.leading, geo.size.width/4)
}
VStack (alignment: .center){
Image(systemName: "flame")
//.ignoresSafeArea(.keyboard)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.padding(.top, 40.0)
}
//.ignoresSafeArea(.keyboard)
.frame(width: geo.size.width, height: geo.size.height)
}
//.ignoresSafeArea(.keyboard)
.offset(y: -35)
}
//.ignoresSafeArea(.keyboard)
.tint(Color.black)
Button {
//Switch views
selectedTab = .favourites
} label: {
GeometryReader { geo in
if selectedTab == .favourites {
Rectangle()
//.ignoresSafeArea(.keyboard)
.foregroundColor(.red)
.frame(width: geo.size.width/2, height: 5)
.padding(.leading, geo.size.width/4)
}
VStack (alignment: .center){
Image(systemName: "star")
//.ignoresSafeArea(.keyboard)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.padding(.top, 40.0)
}//.ignoresSafeArea(.keyboard)
.frame(width: geo.size.width, height: geo.size.height)
}
//.ignoresSafeArea(.keyboard)
.offset(y: -35)
}
//.ignoresSafeArea(.keyboard)
.tint(Color.black)
Button {
//Switch views
selectedTab = .settings
} label: {
GeometryReader { geo in
if selectedTab == .settings {
Rectangle()
//.ignoresSafeArea(.keyboard)
.foregroundColor(.red)
.frame(width: geo.size.width/2, height: 5)
.padding(.leading, geo.size.width/4)
}
VStack (alignment: .center){
Image(systemName: "gear")
//.ignoresSafeArea(.keyboard)
.resizable()
.scaledToFit()
.frame(width: 24, height: 24)
.padding(.top, 40.0)
}//.ignoresSafeArea(.keyboard)
.frame(width: geo.size.width, height: geo.size.height)
}
//.ignoresSafeArea(.keyboard)
.offset(y: -35)
}
//.ignoresSafeArea(.keyboard)
.tint(Color.black)
}
//.ignoresSafeArea(.keyboard, edges: .all)
.frame(height: 20)
}
}
struct TabBar_Previews: PreviewProvider {
static var previews: some View {
TabBar(selectedTab: .constant(.home))
.ignoresSafeArea(.keyboard)
}
}
ignoresSafeArea is commented in all the places I tried to put it.
Here is also the code for the search bar, maybe I need to input ignoreSafeArea somewhere here?
import SwiftUI
struct SearchBarView: View {
#StateObject var im = SearchBarContents()
//#State var selectedTabs: SearchB = .search
#State private var query = ""
var body: some View {
NavigationView {
List {
ForEach(im.filteredData) { item in
HStack{
NavigationLink(destination: ItemView(item: item))
{
SBarView(item: item)
}
}
}
}
.navigationTitle("Items")
.searchable(text: $query,
placement: .navigationBarDrawer(displayMode: .always),
prompt: "Find an Item") {
}
.onSubmit(of: .search) {
im.search(with: query)
}
.onChange(of: query) { newQuery in
im.search(with: newQuery)
}
.onAppear {
im.search()
}
}
}
}
struct SearchBarView_previews: PreviewProvider {
static var previews: some View {
SearchBarView()
}
}
If there is anything missing please let me know.
Imgur link to see exactly what I mean
https://imgur.com/fv79bKh
https://imgur.com/a/Rx9Ki6c (after I add ignoresafearea)
Depends on how you have set up your project. If you have a RootView which is controlling the View to be displayed based on the selection of your Tab Bar and is also the location in the project that you would add the Custom Tab Bar, then on that root View add the modifier .ignoresSafeArea(.keyboard)
For example:
enum Tabs: Int {
case home = 0
case hot = 1
case favourites = 2
case settings = 3
}
struct RootView: View {
#State private var selectedTab = Tabs.home
var body: some View {
VStack {
switch selectedTab {
case .home:
HomeView()
case .hot:
HotView()
case .favourites:
FavouritesView()
case .settings:
SettingsView()
}
Spacer()
CustomTabBar(selectedTab: $selectedTab)
}
.ignoresSafeArea(.keyboard)
}
}

How to expand Detail View to full screen with SwiftUI?

I have a list view embedded in a Navigation View, however, this Navigation View is only about the screen height. This list links to a detailed view, and when a row is tapped, the Detail View only takes up half of the screen. I would like it to open a completely new window.
Screenshots:
The code is used is the following:
import SwiftUI
import CoreData
extension UIScreen{
static let screenWidth = UIScreen.main.bounds.size.width
static let screenHeight = UIScreen.main.bounds.size.height
static let screenSize = UIScreen.main.bounds.size
}
let topCardHeight: CGFloat = 350
struct HomeView: View {
#Environment(\.managedObjectContext) var moc
#FetchRequest(entity: SavedPoem.entity(), sortDescriptors: []) var savedpoems : FetchedResults<SavedPoem>
var body: some View {
VStack {
VStack (alignment: .center){
Text("Today's Poem, November 18th...")
.font(.subheadline)
.foregroundColor(.white)
.padding(.bottom)
.padding(.top, 75)
Text("No Man Is An Island")
.font(.largeTitle)
.fontWeight(.heavy)
.foregroundColor(.white)
.padding(.bottom,1)
Text("by John Donne")
.font(.largeTitle)
.fontWeight(.heavy)
.foregroundColor(.white)
.padding(.bottom, 35)
Button(action: {}) {
Text("Read Now")
.fontWeight(/*#START_MENU_TOKEN#*/.bold/*#END_MENU_TOKEN#*/)
.font(.subheadline)
.foregroundColor(.white)
.padding(15)
.border(Color.white, width: 3)
}
}
.frame(width: UIScreen.screenWidth, height: topCardHeight, alignment: .top)
.background(Color.black)
.edgesIgnoringSafeArea(.top)
.edgesIgnoringSafeArea(.bottom)
.padding(.bottom, 0)
NavigationView{
List{
ForEach(savedpoems, id:\.title) {SavedPoem in
NavigationLink (destination: ContentView()){
ZStack {
Rectangle().fill(Color.white)
.frame(width: UIScreen.main.bounds.width - 32, height: 70)
.cornerRadius(10).shadow(color: .gray, radius: 4)
HStack {
VStack (alignment: .leading){
Text("\(SavedPoem.title ?? "")").font(.headline)
.lineLimit(1)
Text("\(SavedPoem.author ?? "")").font(.subheadline)
.foregroundColor(.secondary)
}
Spacer()
}.padding()
}
// }.onDelete(perform: remove)
}
}
}
.navigationTitle("My Saved Poems")
.navigationBarHidden(true)
.edgesIgnoringSafeArea(.top)
.padding(.top, 0)
}
}
// func remove(at offsets : IndexSet) {
// for index in offsets {
// let delete = SavedPoem[index]
// self.moc.delete(delete)
// }
// try? self.moc.save()
// }
}
Any ideas? Thanks in advance.
If you need the same UI:
(The navigation view at the bottom of your top view) , here is a solution for it .
var body: some View {
#EnvironmentObject var sharedViewModel : SharedViewModel
VStack {
VStack (alignment: .center){
if sharedViewModel.currentPageIsHome {
// your top view body here ..
}
}
NavigationView{\*....*\}
}
}.onAppear {
sharedViewModel.currentPageIsHome = true
}.onDisappear {
sharedViewModel.currentPageIsHome = false
}
And you need to create an Observable object
class SharedViewModel: ObservableObject {
#Published var currentPageIsHome = false
}
And don't forget to initialize it in your SceneDelegate
ContentView().environmentObject(SharedViewModel())
Or
Clear version :
change your view hierarchy to :
NavigationView {
List{
Section(header: YourTopView()) {
// ... your list content
}
}
}

SwiftUI Keyboard Shortcuts Not Working In Toolbar Or Menus

SwiftUI keyboard shortcuts do not appear to work at all when the button is in a Menu and they only work in certain ToolbarItem Placements such as bottomBar.
I've put together this demo app to show the current behavior.
Unfortunately I think this is a SwiftUI bug but can anyone figure out a way to get these working, especially the buttons in Menus.
This is tested with Xcode 12.2 and iOS 14.2.
Feedback number: FB8895536
struct ContentView: View{
#State private var tabSelection = Tab.navigationBarItemTest
enum Tab {
case navigationBarItemTest
case navigationBarMenuTest
case toolbarItemTest
case ToolbarItemMenuTest
}
var body: some View{
TabView(selection: $tabSelection) {
NavigationBarItemTest()
.tabItem {
Label("Nav Bar", systemImage: "1.circle")
}
.tag(Tab.navigationBarItemTest)
NavigationBarMenuTest()
.tabItem {
Label("Nav Bar Menu", systemImage: "2.circle")
}
.tag(Tab.navigationBarMenuTest)
ToolbarItemTest()
.tabItem {
Label("Toolbar Bar", systemImage: "3.circle")
}
.tag(Tab.toolbarItemTest)
ToolbarItemMenuTest()
.tabItem {
Label("Toolbar Bar Menu", systemImage: "4.circle")
}
.tag(Tab.ToolbarItemMenuTest)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct NavigationBarItemTest: View{
#State private var show1 = false
var body: some View{
NavigationView{
Color.blue
.frame(width: 200, height: 200)
.cornerRadius(10)
.navigationBarTitle("1")
.frame(width: 200, height: 200)
.cornerRadius(10)
.sheet(isPresented: $show1, content: {
Color.blue
})
.navigationBarItems(trailing:
Button("Show"){
show1.toggle()
}.keyboardShortcut("1", modifiers: .command)
)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct NavigationBarMenuTest: View{
#State private var show2 = false
var body: some View{
NavigationView{
Color.red
.frame(width: 200, height: 200)
.cornerRadius(10)
.navigationBarTitle("2")
.frame(width: 200, height: 200)
.cornerRadius(10)
.sheet(isPresented: $show2, content: {
Color.red
})
.navigationBarItems(trailing:
Menu{
Button("Show"){
show2.toggle()
}.keyboardShortcut("2", modifiers: .command)
} label: {
Image(systemName: "plus")
}
)
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct ToolbarItemTest: View{
#State private var show3 = false
var body: some View{
NavigationView{
Color.green
.frame(width: 200, height: 200)
.cornerRadius(10)
.navigationBarTitle("3")
.frame(width: 200, height: 200)
.cornerRadius(10)
.sheet(isPresented: $show3, content: {
Color.green
})
.toolbar{
ToolbarItem(placement: .navigationBarTrailing) {
Button("Show"){
show3.toggle()
}.keyboardShortcut("3", modifiers: .command)
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
struct ToolbarItemMenuTest: View{
#State private var show4 = false
var body: some View{
NavigationView{
Color.yellow
.frame(width: 200, height: 200)
.cornerRadius(10)
.navigationBarTitle("4")
.frame(width: 200, height: 200)
.cornerRadius(10)
.sheet(isPresented: $show4, content: {
Color.yellow
})
.toolbar{
ToolbarItem(placement: .navigationBarTrailing) {
Menu{
Button("Show"){
show4.toggle()
}.keyboardShortcut("4", modifiers: .command)
} label: {
Image(systemName: "plus")
}
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
}
}

Why my ObservableObject seems to be broken with a specific view?

I have created a class for keeping the trace a the actual view (a simple ObservableObject String) :
import Foundation
import SwiftUI
import Combine
class ViewRouter: ObservableObject {
#Published var currentView: String
init() {
self.currentView = "Home"
}
}
I have create a simple custom TabView and it works very well with this :
import SwiftUI
struct Test2CustomTabView: View {
#ObservedObject var viewRouter = ViewRouter()
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
if self.viewRouter.currentView == "Home" {
Home()
} else if self.viewRouter.currentView == "Messages" {
Messages()
}
Spacer()
HStack {
VStack {
Image(systemName: "house")
Text("Home")
.font(.caption)
}.frame(width: geometry.size.width/2, alignment: .center)
.offset(y: -15)
.onTapGesture {
self.viewRouter.currentView = "Home"
}
VStack {
Image(systemName: "envelope")
Text("Messages")
.font(.caption)
}.frame(width: geometry.size.width/2, alignment: .center)
.offset(y: -15)
.onTapGesture {
self.viewRouter.currentView = "Messages"
}
}.frame(height: 85)
.foregroundColor(.white)
.background(Color(#colorLiteral(red: 0.259467423, green: 0.5342320204, blue: 0.7349982858, alpha: 1))) // On utilise ici extension Color plus bas
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
I want to simplify the code so i created this view :
import SwiftUI
struct Test2CustomTabViewItem: View {
#ObservedObject var viewRouter = ViewRouter()
var systemName:String
var viewName:String
let screenSize: CGRect = UIScreen.main.bounds
var body: some View {
VStack {
Image(systemName: systemName)
Text("Home")
.font(.caption)
}.frame(width: screenSize.width/2, alignment: .center)
.offset(y: -15)
.onTapGesture {
self.viewRouter.currentView = self.viewName
}
}
}
struct Test2CustomTabViewItem_Previews: PreviewProvider {
static var previews: some View {
Test2CustomTabViewItem(systemName: "house", viewName: "Home")
}
}
And now im using the Test2CustomTabView like this :
import SwiftUI
struct Test2CustomTabView: View {
#ObservedObject var viewRouter = ViewRouter()
var body: some View {
GeometryReader { geometry in
VStack {
Spacer()
if self.viewRouter.currentView == "Home" {
Home()
} else if self.viewRouter.currentView == "Messages" {
Messages()
}
Spacer()
HStack {
Test2CustomTabViewItem(systemName: "house", viewName: "Home")
Test2CustomTabViewItem(systemName: "envelope", viewName: "Messages")
}.frame(height: 85)
.foregroundColor(.white)
.background(Color(#colorLiteral(red: 0.259467423, green: 0.5342320204, blue: 0.7349982858, alpha: 1))) // On utilise ici extension Color plus bas
}
}
.edgesIgnoringSafeArea(.bottom)
}
}
struct Test2CustomTabView_Previews: PreviewProvider {
static var previews: some View {
Test2CustomTabView()
}
}
But now when i click on the custom tabview item the view are not refreshed, the change in the ObservableObject doesn't refresh the view and i dont understand why..
Any idea?
Thanks
In your code each view has his own ViewRouter instance. Pass it to Test2CustomTabViewItem view from the constructor or as environmentObject:
struct Test2CustomTabViewItem: View {
#ObservedObject var viewRouter: ViewRouter
var systemName:String
var viewName:String
...
}
struct Test2CustomTabView: View {
#ObservedObject var viewRouter = ViewRouter()
...
Test2CustomTabViewItem(viewRouter: self.viewRouter, systemName: "house", viewName: "Home")
Test2CustomTabViewItem(viewRouter: self.viewRouter, systemName: "envelope", viewName: "Messages")
...
}

How do I implement #EnvironmentObject for this custom full-screen modal setup?

My goal is to have custom modals present over an root view that is essentially a tabbed view. So, I wrapped the TabView in a ZStack and am using an ObservableOBject. But I don't feel I'm doing it the right way.
In my other file, I have the Custom modal "subviews" which has an enum, too, which I think is the right approach to take. But I cannot figure out how to dismiss a modal after it is visible.
It must be #EnvironmentObject, but I don't know what if anything to put in the scene delegate, etc. ("Hacking with Swift" is failing me here, although it's a great resource.)
My idea is that views from the tabbed view will have various buttons which present different modal views, populated later with data specific to say a user and set of fields for data entry.
Right now, I just want to understand how to present and dismiss them.
Here is my root view
import SwiftUI
struct ContentView: View {
#ObservedObject var modal = CustomModal()
var body: some View {
ZStack {
TabView {
ZStack {
Color.pink.opacity(0.2)
Button(action: {
withAnimation{
self.modal.visibleModal = VisibleModal.circle
}
}) {
Text("Circle").font(.headline)
}
.frame(width: 270, height: 64)
.background(Color.pink.opacity(0.5)).foregroundColor(.white)
.cornerRadius(12)
}
.tabItem{
VStack{
Image(systemName: "1.square.fill")
Text("One")
}
}.tag(1)
ZStack {
Color.blue.opacity(0.2)
Button(action: {
self.modal.visibleModal = VisibleModal.squircle
}) {
Text("Square").font(.headline)
}
.frame(width: 270, height: 64)
.background(Color.blue.opacity(0.5)).foregroundColor(.white)
.cornerRadius(12)
}
.tabItem{
VStack{
Image(systemName: "2.square.fill")
Text("Two")
}
}.tag(2)
}.accentColor(.purple)
VStack {
containedView()
}
}
}
func containedView() -> AnyView {
switch modal.visibleModal {
case .circle: return AnyView(CircleView())
case .squircle: return AnyView(SquircleView())
case .none: return AnyView(Text(""))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
And here is my second file with the enum and "subview" modals
import SwiftUI
class CustomModal: ObservableObject {
#Published var visibleModal: VisibleModal = VisibleModal.none
}
enum VisibleModal {
case circle, squircle, none
}
struct CircleView: View {
var body: some View {
ZStack {
Color.pink.blur(radius: 0.4)
Circle().fill()
.frame(width: 300)
.foregroundColor(Color.white.opacity(0.75))
dismissButton()
}.edgesIgnoringSafeArea(.all)
}
}
struct SquircleView: View {
var body: some View {
ZStack{
Color.green.blur(radius: 0.4)
RoundedRectangle(cornerRadius: 48, style: .continuous)
.frame(width: 300, height: 300).foregroundColor(Color.white.opacity(0.75))
dismissButton()
}.edgesIgnoringSafeArea(.all)
}
}
struct dismissButton: View {
#ObservedObject var modal = CustomModal()
var body: some View {
VStack{
Spacer()
Button(action: {
self.modal.visibleModal = VisibleModal.none
}) {
Text("Dismiss").font(.headline)
}
.frame(width: 270, height: 64)
.background(Color.white.opacity(0.35)).foregroundColor(.white)
.cornerRadius(12)
.padding(.bottom, 44)
}
}
}
Are you just trying to pass your observable object to the new view?
func containedView() -> some View {
switch modal.visibleModal {
case .circle: return CircleView()
.environmentObject(self.modal)
case .squircle: return SquircleView()
.environmentObject(self.modal)
case .none: return Text("")
}
}
Unless I am misunderstanding the question.
Okay, after a lot of fiddling, it works.
Now my code is as follows.
Root view
struct ContentView: View {
#EnvironmentObject var isModalVisible: CustomModal
#ObservedObject var modal = CustomModal()
var body: some View {
ZStack {
TabView {
ZStack {
Color.pink.opacity(0.2)
Button(action: {
withAnimation{
self.isModalVisible.isModalVisible.toggle()
self.modal.currentModal = VisibleModal.circle
}
}) {
Text("Circle").font(.headline)
}
.frame(width: 270, height: 64)
.background(Color.pink.opacity(0.5)).foregroundColor(.white)
.cornerRadius(12)
}
.tabItem{
VStack{
Image(systemName: "1.square.fill")
Text("One")
}
}.tag(1)
ZStack {
Color.blue.opacity(0.2)
Button(action: {
self.isModalVisible.isModalVisible.toggle()
self.modal.currentModal = VisibleModal.squircle
}) {
Text("Square").font(.headline)
}
.frame(width: 270, height: 64)
.background(Color.blue.opacity(0.5)).foregroundColor(.white)
.cornerRadius(12)
}
.tabItem{
VStack{
Image(systemName: "2.square.fill")
Text("Two")
}
}.tag(2)
}.accentColor(.purple)
if self.isModalVisible.isModalVisible {
VStack {
containedView()
}
}
}
}
func containedView() -> AnyView {
switch modal.currentModal {
case .circle: return AnyView(CircleView())
case .squircle: return AnyView(SquircleView())
case .none: return AnyView(Text(""))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView().environmentObject(CustomModal())
}
}
and the second file with the supporting views and classes and enums:
import SwiftUI
class CustomModal: ObservableObject {
#Published var isModalVisible = false
#Published var currentModal: VisibleModal = .none
}
enum VisibleModal {
case circle, squircle, none
}
struct CircleView: View {
#EnvironmentObject var env: CustomModal
var body: some View {
ZStack {
Color.pink.blur(radius: 0.4)
Circle().fill()
.frame(width: 300)
.foregroundColor(Color.white.opacity(0.75))
dismissButton()
}.edgesIgnoringSafeArea(.all)
}
}
struct SquircleView: View {
var body: some View {
ZStack{
Color.green.blur(radius: 0.4)
RoundedRectangle(cornerRadius: 48, style: .continuous)
.frame(width: 300, height: 300).foregroundColor(Color.white.opacity(0.75))
dismissButton()
}.edgesIgnoringSafeArea(.all)
}
}
struct dismissButton: View {
#EnvironmentObject var env: CustomModal
var body: some View {
VStack{
Spacer()
Button(action: {
self.env.isModalVisible.toggle()
print("TAPPED")
}) {
Text("Dismiss").font(.headline)
}
.frame(width: 270, height: 64)
.background(Color.white.opacity(0.35)).foregroundColor(.white)
.cornerRadius(12)
.padding(.bottom, 44)
}
}
}
It still can be refactored. I'm sure. I'd also be happy to hear any comments on how to improve it. But it seems to work.
NOTE: This code ContentView().environmentObject(CustomModal()) is put in the previewP{rovider code and in SceneDelegate.