How can I hide title bar in SwiftUI? (for MacOS app) - swift

there πŸ‘‹
I know hide title bar in Storyboard.
But I can't find the way in SwiftUI.
I want to hide title bar with control buttons and make floating image view.
Let me know please.
If you know related example, tell me please.
My little english sorry.. πŸ™‡

import SwiftUI
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}.windowStyle(HiddenTitleBarWindowStyle())
}
}
try HiddenTitleBarWindowStyle()

Removing the Title Bar in Your Mac App Built with Mac Catalyst
Display content that fills the entire height of a window by removing the title bar.
By default, Mac apps built with Mac Catalyst display a title bar across the top of their windows. A horizontal line separates the title bar from the content of the window.
Some Mac apps such as Messages and Contacts have no title bar in their main window. Instead, the top of the window shows only the Close, Minimize, and Zoom buttons with no separator between them and the window's content. In this UI design, the content area fills the entire height of the window.
The following image illustrates these styles in two windows. The first window displays a title bar, while the second has none.
Screenshot of two windows, one stacked above the other, with a dark background in the content area of each window.
Remove the Title Bar
If you choose to design your window without a title bar, you must remove it from the window. To remove the title bar, set the title bar’s titleVisibility property to UITitlebarTitleVisibility.hidden and the toolbar property to nil. The following code shows how to remove the title bar and its separator from the window during the setup of a new scene.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
#if targetEnvironment(macCatalyst)
if let titlebar = windowScene.titlebar {
titlebar.titleVisibility = .hidden
titlebar.toolbar = nil
}
#endif
}
Click here for more information

I could not find a way to hide the toolbar entirely in SwiftUI. But this is a possible workaround. You can put this code in your AppDelegate file.
func applicationDidFinishLaunching(_ aNotification: Notification) {
let window = NSApplication.shared.windows.first!
window.titlebarAppearsTransparent = true
window.backgroundColor = .white
window.standardWindowButton(.closeButton)!.isHidden = true
window.standardWindowButton(.miniaturizeButton)!.isHidden = true
window.standardWindowButton(.zoomButton)!.isHidden = true
}
Using this code will make it appear that the toolbar is hidden when in reality, it is still there. But the buttons are hidden, and the background is transparent.

Related

How to customize MCBrowserViewController in swift for macOS?

Currently I browse a session using the following:
let mcBrowser = MCBrowserViewController(serviceType: "service", session: p2pSession)
mcBrowser.delegate = self
mcBrowser.maximumNumberOfPeers = 1
listVC.presentAsModalWindow(mcBrowser)
Which produces a view:
I want to know if there's way to customize the appearance of the view controller before it's presented? For instance change the back ground of the list view to be dark instead of white. Or perhaps add an additional button to the window.

iOS 14 UISplitViewController (sidebar) with triple column sidebar toggle icon behavior

I'm implementing the iOS 14 (iPadOS 14) sidebar (UISplitViewController with TripleColumn) and having strange "sidebar toggle icon" behavior.
In iOS 13 I'm using the tab bar with some split views and table views so I need the Triple Column instead of the Double Column to work.
For example, using the sidebar in "flights" tab needs three columns:
And there are some tabs with only one column (in iOS 13, it was a table view instead of a split view). I set the supplementary view to nil, and hide the view by calling "hide" method implemented in iOS 14. (See below for code):
The "sidebar toggle icon" on the upper left is automatically displayed. After clicking the toggle icon, the sidebar hides correctly but an "back button" was created on my secondary view(a UITableViewController embedded in a UINavigationController):
Pressing (clicking) the back button has no response. User can still swipe from the left edge of the screen to make sidebar reappear but the "back button" is confusing. My expected behavior is, after the toggle icon selected in sidebar, display the "sidebar toggle icon" instead of the "back button" in the secondary view. And after pressing the "sidebar toggle icon" in secondary view, the sidebar reappears.
Like the Photos app in iOS 14 (iPadOS 14), the toggle button is shown instead of the back button. And clicking the toggle icon will make the sidebar shown again. (but it's a double column split view)
My code:
SceneDelegate.swift:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
if #available(iOS 14.0, *) {
let main = UIStoryboard(name: "Main", bundle: nil)
let splitViewController = UISplitViewController(style: .tripleColumn)
splitViewController.preferredDisplayMode = .twoBesideSecondary
splitViewController.preferredSplitBehavior = .tile
splitViewController.setViewController(SideBarViewController(), for: .primary)
// fall back for compact screen
splitViewController.setViewController(main.instantiateInitialViewController(), for: .compact)
window.rootViewController = splitViewController
self.window = window
window.makeKeyAndVisible()
}
}
}
SideBarViewController:
// if the first tab (dashboard) was selected
private func selectDashboardTab() {
if #available(iOS 14.0, *) {
let dashboardVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DashboardTab") as? UINavigationController
splitViewController?.preferredPrimaryColumnWidth = 250.0
splitViewController?.preferredDisplayMode = .twoBesideSecondary
splitViewController?.preferredSplitBehavior = .tile
splitViewController?.setViewController(dashboardVC, for: .secondary)
splitViewController?.setViewController(nil, for: .supplementary)
splitViewController?.hide(.supplementary)
}
}
I was able to reproduce the problem... but was unable to circumvent it using the available API. Apple stubbornly decided that the sidebar icon would always be in the supplementary controller when in a 3-column layout, it seems.
That being said, I've coded a hack to fix it. I managed to create a UISplitViewController subclass that "fakes" an editable style property, thus allowing us to set the number of columns (the hack just creates a brand new controller and makes it the new rootViewController).
The hack allows us to switch between 2-colulm and 3-column layout at will, and seems to solve the sidebar icon problem.
Link to the Xcode project below. But here's the gist of it:
class AdaptableSplitViewController: UISplitViewController {
override var style: Style {
get {
super.style
}
set {
guard newValue != style else { return }
let primaryController = viewController(for: .primary)
let supplementaryController = viewController(for: .supplementary)
let secondaryController = viewController(for: .secondary)
let newSplitController = AdaptableSplitViewController(style: newValue)
newSplitController.setViewController(primaryController , for: .primary)
newSplitController.setViewController(secondaryController, for: .secondary)
if newValue == .tripleColumn {
newSplitController.setViewController(supplementaryController, for: .supplementary)
}
UIApplication.shared.windows[0].rootViewController = newSplitController
}
}
}
Let me know if this helps.
Link to the zipped Xcode sample project
Late in the discussion but... I've encountered a similar behavior.
Just before setting you secondary, set it to nil. Strange, I know, but it fixed it for me. Like this:
splitViewController?.setViewController(nil , for: .secondary)
splitViewController?.setViewController(dashboardVC, for: .secondary)

Snapshot of screen shows toolbar on device but not on simulator

I have a toolbar that's instantiated on viewDidLoad on top of a webkit. When I take a snapshot on the simulator, the toolbar is missing which is what I would like. When built on the device, the toolbar is there.
I tried to hide the toolbar with:
toolbar.isHidden = true
but the application crashes with toolbar being nil. If I change it to:
toolbar?.isHidden = true
It still shows up considering it still thinks it's nil.
The toolbar is set up on viewDidLoad by calling another function:
var toolbar : UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
setUpToolBar()
}
func setUpToolBar() {
let saveButton = UIBarButtonItem(barButtonSystemItem: .save, target: self, action: #selector(takeScreenshot))
...
let toolbar = UIToolbar(frame: CGRect(x: 0, y: 300, width: 200, height: 50))
toolbar.setItems([saveButton,flexibleSpaceFillerLeft,userAgentButton,flexibleSpaceFillerRight,doneButton], animated: true)
view.addSubview(toolbar)
}
The code for my snapshot is below. This is where I tried to hide the toolbar before taking the snapshot.
#objc func takeScreenshot() {
webView.takeSnapshot(with: nil, completionHandler: { (image,error) in
if let image = image {
self.screenshotOfWindow = image
self.showScreenshotEffect()
self.saveAllData()
} else {
print (error?.localizedDescription as Any)
}
})
}
Here's the screen I need to take a screenshot of:
The red box in the screenshot is the bar that I need to disappear from the screenshot.
I'd like to be able to take the screenshot without the bottom bar in view. As stated before, this works in the simulator, but the device always shows the bar. There's also a "navigation controller" gap at the top of the screenshot since the top bar covers part of the screen at top, but this is just blank and something I can address later.
I just wanted to come back and answer how I solved this. The webview is embedded in a navigation controller, but I was creating the toolbar programmatically on viewDidLoad by calling a setupToolBar function I had created early on in the project. I could hide the toolbar, but it was still being captured while taking the screenshot. I commented all of that code out and used the navigation controller's toolbar instead. Now when I take the screenshot, the bottom and top bar of the navigation controller is not part of the screenshot.

Swift iOS -How to Add Subview to Window's Center?

I have an activity indicator that gets presented on an iPhone and iPad. In the iPad in split screen mode it gets presented to whichever side of the view that called it. I would instead like it to get presented in the middle/center the window's screen. If I do it this way wether on the iPhone in portrait or iPad in split screen mode it will always be in the center of the screen.
How do I do this?
MyView: UIViewController{
let actInd = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge)
#IBAction fileprivate func buttonPressed(_ sender: UIButton) {
guard let window = UIApplication.shared.keyWindow else { return }
//how to add actInd as subview to the window' screen?
actInd.startAnimating()
}
}
It's pretty simple. Turn off the auto-resizing mask. Add the add actInd to window, then set the center anchors.
actInd.translatesAutoresizingMaskIntoConstraints = false
window.addSubview(actInd)
actInd.centerXAnchor.constraint(equalTo: window.centerXAnchor).isActive = true
actInd.centerYAnchor.constraint(equalTo: window.centerYAnchor).isActive = true
Window is subclass of UIView. Just add it as it's subview like you're adding a view to another view. But remember that window is shared throughout your app, so adding it every-time will consume memory, remove it after your job is done.
If you want to center it in the window, you can use autoResizingMask or add constraints to it.

Modal Panel with rounded corners

I'm wondering if there is a way to display a modal window with rounded corners instead of the default sharp corners. The image shows what corners I'm referring to.
I tried with changing the contentView.layer?.cornerRadius but it didn't work. What can I do to get the result I need?
After working a lot on it, I finally found a solution:
Frist create a new borderless window in your interface builder. Place a custom box in that view and make sure it leaves a bit of space from the top border of the window:
Then add an outlet of that window object in your app delegate:
#IBOutlet weak var saveWindow: NSWindow!
So copy that extension for loading and dismissing a panel as a modal sheet:
extension NSWindow {
public func loadPanel(named: NSWindow) {
named.isOpaque = false
named.backgroundColor = NSColor.clear
named.hasShadow = false
self.beginSheet(named, completionHandler: nil)
}
public func closePanel(named: NSWindow) {
self.endSheet(named)
}
}
You just need to call this two functions if you want to open a panel.
window.loadPanel(named: saveWindow)
And when you're done:
window.closePanel(named: saveWindow)
This is the result: