I Created Floating Menu in SwiftUI, but i am stuck in one issue, When press on bottom right plus button i open floating menu items and again press on plus button hide that floating menu items, but when press on menu items it will not hide that menu items.
Below is my code
MapContainerUIView.swift
struct MapContainerUIView: View {
let flotingMenuArray = [
MenuItemModel(title: "Camera", icon: "camera.fill"),
MenuItemModel(title: "Photo", icon: "photo.on.rectangle"),
MenuItemModel(title: "Share", icon: "square.and.arrow.up.fill")
]
var body: some View {
NavigationView{
ZStack {
FloatingMenu(dataSource: flotingMenuArray)
}
}
}
func floatingButtonAction(index: Int){
print("Floating item tap", index)
}
}
FloatingMenu.swift
struct FloatingMenu: View {
init() {
self.dataSource = []
}
init(dataSource: [MenuItemModel]) {
self.dataSource = dataSource
}
@State var isMenuShow = false
var dataSource: [MenuItemModel]
var body: some View {
ZStack(alignment: .trailing){
if isMenuShow{
Button(action: {
self.showMenu()
}) {
Text("")
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.black)
.opacity(0.3)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.all)
}
HStack{
Spacer()
VStack(alignment: .trailing, content: {
Spacer()
ForEach(0..<dataSource.count) { index in
if isMenuShow {
MenuItems(menuItemData: dataSource[index], index: index)
}
}
Button(action: {
self.showMenu()
}) {
Image(systemName: "plus.circle.fill")
.resizable()
.frame(width: 60, height: 60)
.foregroundColor(Color.white)
}
.background(Color.black)
.cornerRadius(35)
})
.shadow(color: .gray, radius: 4, x: 1, y: 1)
.padding(.init(top: 0, leading: 20, bottom: 20, trailing: 20))
}
}
}
func showMenu() {
self.isMenuShow.toggle()
}
}
MenuItems.swift
class MenuItemModel : Identifiable{
var id = UUID()
var title : String = ""
var icon : String = ""
init(title: String, icon: String) {
self.title = title
self.icon = icon
}
}
struct MenuItems: View {
var mapContainer = MapContainerUIView()
var menuItemData: MenuItemModel
var index : Int
var body: some View {
ZStack {
HStack{
Text(menuItemData.title)
.foregroundColor(.white)
.shadow(color: .gray, radius: 3, x: 1, y: 1)
Button(action: {
FloatingMenu().isMenuShow = false
print("button tap: ", menuItemData.title)
self.mapContainer.floatingButtonAction(index: index)
}) {
ZStack {
Circle()
.foregroundColor(Color.white)
.frame(width: 45, height: 45)
.shadow(color: .gray, radius: 3, x: 1, y: 1)
Image(systemName: menuItemData.icon)
.imageScale(.large)
.foregroundColor(.black)
}
.padding(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 10))
}
}
}
}
}
I want to hide floating menu when press on menu items, please someone guide me.
Right now, you're trying to set isMenuShow
on a new instance of FloatingMenu
, which is why it isn't working.
One solution is to pass a Binding
from the original FloatingMenu
instance.
struct MenuItems: View {
@Binding var isMenuShow : Bool //<-- Here
var mapContainer = MapContainerUIView()
var menuItemData: MenuItemModel
var index : Int
var body: some View {
ZStack {
HStack{
Text(menuItemData.title)
.foregroundColor(.white)
.shadow(color: .gray, radius: 3, x: 1, y: 1)
Button(action: {
self.isMenuShow = false //<-- Here
print("button tap: ", menuItemData.title)
self.mapContainer.floatingButtonAction(index: index)
}) {
And, in FloatingMenu:
if isMenuShow {
MenuItems(isMenuShow: $isMenuShow, //<-- Here
menuItemData: dataSource[index],
index: index)
}
Another solution would be to provide a closure as an argument to MenuItems
that closes the menu:
struct MenuItems: View {
var closeMenu : () -> Void //<-- Here
var mapContainer = MapContainerUIView()
var menuItemData: MenuItemModel
var index : Int
var body: some View {
ZStack {
HStack{
Text(menuItemData.title)
.foregroundColor(.white)
.shadow(color: .gray, radius: 3, x: 1, y: 1)
Button(action: {
closeMenu() //<-- Here
print("button tap: ", menuItemData.title)
//self.mapContainer.floatingButtonAction(index: index)
}) {
if isMenuShow {
MenuItems(closeMenu: { self.isMenuShow = false },
menuItemData: dataSource[index],
index: index)
}