SwiftUI detect when contextMenu is open - ios

As the title says, is there any way I can detect (e.g. using a #State variable) when either any context menu is open, or the context menu of a specific view is open?
As a basic idea, I would like to print something if it is open. This does not work:
.contextMenu {
print("open")
}
This also does not seem to work:
.contextMenu {
EmptyView()
.onAppear {
print("open")
}
}
How could i make this work?
Edit: Why i think its even possible to do it or at least possible to make it look like its possible: On instagram, one can see individual posts as a square only. However using long-press, a context menu opens, and now the post shape is different, but even more there is also a small title above it.. How would one do that? Did they modify the view when the context menu open or is the grid view the post is in before just hiding those details (true image shape + image title) but they are rendered already?
Screenshots:

A possible approach is to use simultaneous gesture for this purpose, like
Text("Demo Menu")
.contextMenu(menuItems: {
Button("Button") {}
})
.simultaneousGesture(LongPressGesture(minimumDuration: 0.5).onEnded { _ in
print("Opened")
})
Tested with Xcode 13.2 / iOS 15.2

Related

How can I permanently show sidebar in a SwiftUI NavigationView or SplitNavigationView exactly like the Apple Settings App on iPad?

I am trying to display a two column NavigationView in my app exactly like the settings on the iPad. With no way to collapse the sidebar on an iPad. I would have thought using a NavigationView with DoubleColumnStyle would work but it doesn't and it's deprecated. I can use a NavigationSplitView like before to control the initial look however the user is still able to collapse the navigation sidebar.
I thought there would be a simple solution to this but have been looking for a while and haven't found any approach that works.
So far I have the following:
struct SettingsView: View {
#State private var columnVisibility = NavigationSplitViewVisibility.doubleColumn
var body: some View {
NavigationSplitView(columnVisibility: $columnVisibility) {
Text("Sidebar")
} detail: {
Text("Detail")
}
}
}
Here both the icon in the top left to hide the sidebar is generated automatically and also dragging the sidebar to the left closes it.

How to show context menu with preview?

I was wondering how to show a context menu when holding an element then showing a preview with the menu items in SwiftUI? I know how to show context menu items, but not with the preview and the animation.
View video: https://utilities.awesomeplayer.tech/send/f.php?h=35h_YJr5&p=1
I have tried to attach views inside the Context Menu, before the Buttons, but that has not worked.
Any help would be appreciated!
NOTE: The following is only available in iOS 16+ and iPadOS 16+. Earlier versions in second part. From the docs:
This view modifier produces a context menu on macOS, but that platform doesn’t display the preview.
Take a look at the docs here: https://developer.apple.com/documentation/swiftui/gridrow/contextmenu(menuitems:preview:). In iOS 16+, contextMenu accepts a preview argument that is some View. Example:
struct myViewWithPreview: View{
var body: some View{
Text("Hold for contextMenu")
.contextMenu{
//ContextMenu stuff here
//Such as buttons
Button("Example"){}
} preview: {//<-- HERE!!!!
//Here, put any view that you want as a preview. For example, you could put a webview here on a link.
//You could also do an image, such as how they do it on the docs.
Text("Preview!")
}
}
}
If you are using earlier OS versions, you must do this using a custom approach. Take a look at this article. This could also be of use: https://onmyway133.com/posts/how-to-show-context-menu-with-custom-preview-in-swiftui/.

Why my SF Icons are automatically filled in Xcode 13 and Ios 15 [duplicate]

I select the systemImage "map" and "person" for the tabItem, but the images are in filled format which must be in hollow format. What's the reason?
struct TestView: View {
var body: some View {
TabView {
Text("Map!")
.tabItem {
Label("Map", systemImage: "map")
}
Text("Profile")
.tabItem {
Label("Person", systemImage: "person")
}
}
}
}
Xcode: 13.1
SF Symbols: 3.1
This is standard SwiftUI behaviour in iOS 15, as it implements by default the recommendations from Apple’s Human Interface Guidelines, which says tab bars should use filled variants of SF Symbols, while sidebars on iPad should use the outline variant.
The effect is achieved by iOS automatically applying the .symbolVariants environment value, as noted in the symbol variants documentation:
SwiftUI sets a variant for you in some environments. For example, SwiftUI automatically applies the fill symbol variant for items that appear in the content closure of the swipeActions(edge:allowsFullSwipe:content:) method, or as the tab bar items of a TabView.
If you absolutely want to get rid of the fill mode, it’s deliberately made tricky but not impossible. You have to override the supplied \.symbolVariants environment variable directly on the Label element, inside your tabItem declaration:
Text("Map!")
.tabItem {
Label("Map", systemImage: "map")
.environment(\.symbolVariants, .none)
}
Using the .symbolVariants(.none) modifier, or trying to set the environment value higher up the view graph, won’t work.
Now that you see how to override the effect, I would still advise using the filled forms in the tab bar. Given that the tab bar no longer has a background colour difference from the rest of the page in many cases, the extra visual weight given to tab items by use of the filled variant lends the right amount of visual weight to those elements.

Have multiple columns in a SwiftUI Form

I am looking to have multiple columns within a SwiftUI form section. I have seen other potential fixes and using .onTapGesture, but that seem's very 'hacky' and doesn't provide the same aesthetics a form normally does on the iPad.
In my code I have one ForEach loop that will have around 15 rows, I want to split these and ensure they all appear on the user's screen at once, therefore eliminating the need to scroll and search.
Section(header: Text("Current Players On the Field")){
ForEach(team.players){player in
if(player.active == true){
Button(action: {
//Button Action Here
}){
PlayerSelectTemplate(player: player)
}
.padding(5)
}
}
}
I have tried implementing LazyV/LazyH Grids in but the buttons all seem to merge and become one, making the separate buttons completely redundant.
As mentioned above, I want to try and avoid the .onTapGesture solve, as it doesn't look as good as having individual buttons. Any ideas?

What is the iOS equivalent of the android three dot menu icon?

Android uses three dots (pictured) to show that there are more menu items available. What is the iOS equivalent of this icon?
It's : ellipsis
and you can use it like this :
Image(systemName: "ellipsis")
There is no clear equivalent, the closest I can think of are the horizontal three dots inside a UITabBarItem when there is no space to show the options:
That being said, contextual menus are not common in iOS apps and there is no default UI item for them.
There is the more system icon from Apple
See all system icons here
If I understand correctly, tapping on the 3 dots shows a new screen with details from the item you've selected? If that's it then on iOS the equivalent is a chevron (>) symbol. It tells you that tapping the entry takes you to a detail screen.
I myself use the "square.and.arrow.up" system icon as my equivalent. Though the Android icon isn't so terrible you could implement it yourself.
Additionally a bottom action sheet is a great equivalent for Android's Contextual Menu.
SwiftUI Implementation of action sheet
.actionSheet(isPresented: $showingActionSheet) {
ActionSheet(title: Text("Change background"), message: Text("Select a new color"), buttons: [
.default(Text("Red")) { self.backgroundColor = .red },
.default(Text("Green")) { self.backgroundColor = .green },
.default(Text("Blue")) { self.backgroundColor = .blue },
.cancel()
])
}
In iOS 14 Apple introduced Pull-Down menus. It should be the closest thing to Android overflow menus. For example, you can add a "more" bar button item to your navigation bar and attach a menu to it.
You can find details about it here: https://developer.apple.com/design/human-interface-guidelines/ios/controls/pull-down-menus/

Resources