Menu bar icon disappears after window resize - ios

I created the default Cocoa macOS project in Xcode and modified AppDelegate so that it adds a menu bar icon and makes the application window fullscreen. What happens instead is that the window appears normally and the menu bar icon (which should be a T) flashes very quickly in the macOS status bar and disappears. If I comment out the code in applicationDidFinishLaunching, the menu bar icon works. If I remove awakeFromNib and don't create a status item, the application becomes fullscreen. If I try to do both at the same time, it won't work, and I would really like to know what I'm doing wrong. This is the main part of my AppDelegate.swift file:
var item = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)
override func awakeFromNib() {
let menu = NSMenu(title: "W")
menu.addItem(NSMenuItem(title: "Quit", action: #selector(AppDelegate.quit), keyEquivalent: ""))
item.title = "T"
item.menu = menu
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
let window = NSApplication.shared.windows.first!
window.setFrame(NSScreen.main!.frame, display: true)
}

Turns out
let window = NSApplication.shared.windows.first!
doesn't return the application window, but it seems to return the menu icon. I changed this to
let window = NSApplication.shared.windows[1]
and it worked.

Related

Get an event when UIBarButtonItem menu is displayed

We all know how to make a simple tap on a bar button item present a menu (introduced on iOS 14):
let act = UIAction(title: "Howdy") { act in
print("Howdy")
}
let menu = UIMenu(title: "", children: [act])
self.bbi.menu = menu // self.bbi is the bar button item
So far, so good. But presenting the menu isn't the only thing I want to do when the bar button item is tapped. As long as the menu is showing, I need to pause my game timers, and so on. So I need to get an event telling me that the button has been tapped.
I don't want this tap event to be different from the producing of the menu; for example, I don't want to attach a target and action to my button, because if I do that, then the menu production is a different thing that happens only when the user long presses on the button. I want the menu to appear on the tap, and receive an event telling me that this is happening.
This must be a common issue, so how are people solving it?
The only way I could find was to use UIDeferredMenuElement to perform something on a tap of the menu. However, the problem is that you have to recreate the entire menu and assign it to the bar button item again inside the deferred menu element's elementProvider block in order to get future tap events, as you can see in this toy example here:
class YourViewController: UIViewController {
func menu(for barButtonItem: UIBarButtonItem) -> UIMenu {
UIMenu(title: "Some Menu", children: [UIDeferredMenuElement { [weak self, weak barButtonItem] completion in
guard let self = self, let barButtonItem = barButtonItem else { return }
print("Menu shown - pause your game timers and such here")
// Create your menu's real items here:
let realMenuElements = [UIAction(title: "Some Action") { _ in
print("Menu action fired")
}]
// Hand your real menu elements back to the deferred menu element
completion(realMenuElements)
// Recreate the menu. This is necessary in order to get this block to
// fire again on future taps of the bar button item.
barButtonItem.menu = self.menu(for: barButtonItem)
}])
}
override func viewDidLoad() {
super.viewDidLoad()
let someBarButtonItem = UIBarButtonItem(systemItem: .done)
someBarButtonItem.menu = menu(for: someBarButtonItem)
navigationItem.rightBarButtonItem = someBarButtonItem
}
}
Also, it looks like starting in iOS 15 there's a class method on UIDeferredMenuElement called uncached(_:) that creates a deferred menu element that fires its elementProvider block every time the bar button item is tapped instead of just the first time, which would mean you would not have to recreate the menu as in the example above.

How to hide PTCardTabBar?

I use PTCardTabBarController like custom tab bar. I want to hide tab bar in my ViewController. I trying to use in storyboard Hide Bottom Bar on Push or in code: self.tabBarController?.tabBar.isHidden = true. But it not helped me.
When I stat to use PTCardTabBar I have next scheme in storyboard:
TabBarController (with class PTCardTabBarController and module PTCardTabBar) -> NavigationBarController -> ViewController.
Next I launch my app and I see under my PTCardTabBar system iOS tab bar. I use in storyboard Hide Bottom Bar on Push but it is hide only system tab bar and not PTCardTabBar. How to fix it and hide both tab bars?
Taking a quick look at that PTCardTabBar library...
What you see on-screen is not a UITabBar ... it is a UIView. So, any normal actions on a standard Tab Bar Controller's TabBar will not be related.
To hide it, you need to edit PTCardTabBarController.swift and make its customTabBar available to your code:
// make this "open"
open lazy var customTabBar: PTCardTabBar = {
return PTCardTabBar()
}()
Then, when you want to hide the tab bar (for example, in viewDidLoad() in your view controller:
if let ptcTBC = tabBarController as? PTCardTabBarController {
ptcTBC.customTabBar.isHidden = true
}
You'll also (obviously) need to set .isHidden back to false to show it again.
Probably, though, you want to do more than just have it showing or hidden... in which case you could further modify PTCardTabBarController.swift to add a function to animate it into or out-of view (for example).

Change TabBar Items after changing app language from inside of app

I have an app and from inside of it I am changing its language.
Language getting properly updated to other screens by changing UIView appearance.
Localize.setCurrentLanguage("ar")
UIView.appearance().semanticContentAttribute = .forceRightToLeft
I'm not able to get control back in my tabcontroller file. TabBar is custom created. I checked with awakefromNib() but it is not getting invocated every time. Is there any tab bar method where I can get control when it appears every time or is there any way to change language of tab bar item titles?
After changing app language in your VC create and call function localizeTabBar():
func localizeTabBar() {
tabBar.items![0].title = "1tab".localized
tabBar.items![1].title = "2tab".localized
tabBar.items![2].title = "3tab".localized
tabBar.items![3].title = "4tab".localized
}
For .localized use this String Extension
Or something like that:
func localizeTabBar() {
tabBar.items?.enumerated().forEach{ (index, item) in
item.title = "\(index)tab".localized
}
}
For .localized use this String Extension

Change toolbars according to the condition

I am working with xamarin android. I have a layout where initially a toolbar with edit will be visible, when user selects edit the current tool bar should be replaced with another toolbar. I have written code as following.
public override bool OnCreateOptionsMenu(IMenu menu)
{
_localMenu = menu;
var toolbar = _isMultiSelect ? Resource.Menu.MultipleFormsDeleteToolBarMenu : Resource.Menu.FormToolbarMenu;
MenuInflater.Inflate(toolbar, menu);
return base.OnCreateOptionsMenu(menu);
}
And when Edit option in first toolbar is selected, Iam calling OnCreateOptionsMenu
else if (item.ItemId == Resource.Id.edit)
{
_isMultiSelect = true;
OnCreateOptionsMenu(_localMenu);
}
Here the problem is,instead of showing second toolbar... the Edit option in first toolbar is replaced by three dots and while tapping on those three dots Edit and Delete options are dislaying.
How can I change those toolbars acconding to the requirements?

UI testing a tab bar controller

I have built a simple tab bar with 3 tabs.
I want to run a UI test to make sure that if the user clicks a tab bar item, the correct view controller shows. How would I go about doing that? Below is the code I would start with, just don't know how to write my assertion.
func testTabBarMyProfileButton() {
let tabBarsQuery = XCUIApplication().tabBars
tabBarsQuery.buttons["My Profile"].tap()
}
func testTabBarGraphsButton() {
let tabBarsQuery = XCUIApplication().tabBars
tabBarsQuery.buttons["Graphs"].tap()
}
func testTabBarAboutButton() {
let tabBarsQuery = XCUIApplication().tabBars
tabBarsQuery.buttons["About"].tap()
}
You can access the tabbar button by its position:
app.tabBars.buttons.element(boundBy: 2).tap()
If you have different controls in each view controller shown on each tab bar, you can make assertions if they exist or not (what is expected).
For example if the first tab bar has UILabel named "First name" you can assert if it exists by writing
Let theLabel = app.staticTexts["myValue"]
XCTAssert(theLabel.exists).to(beTrue)
And on the other screens do the same thing for the different controls.
If anyone finds this looking to UI test the contents of another app, I just found a solution..
The tab bar item is a lazy variable and needs to be touched before you can reference a tab bar button by value. Add this line:
tabBarItem.accessibilityIdentifier = "my-snazzy-identifier"
to the viewDidLoad method and you should be able to do this in your UI tests:
app.tabBars.buttons["Button Title"].tap()
You can test the title of the navigation bar.
XCTAssert(app.navigationBars["Graphs"].exists)
See my GitHub repo for a more detailed UI Testing example.

Resources