tvOS: A way to have UISearchController not appear as a button? - swift2

This code
var searchController: UISearchController!
#IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.obscuresBackgroundDuringPresentation = false
view.addSubview(searchController.searchBar)
getItems()
}
produces this:
Screeshot1
Note that the searchBar appears as a button stuck in the upper left (because this is a tabbed app it appears under the tab bar when first presented. The "Button" button is there to receive focus for testing).
This is how it looks after pressing the button: Screenshot2
The second image shows how I would like things to look when the search tab opens, and the way I though it was supposed to look in tvOS.
How do I get the searchController to appear as it does in the second screenshot? Many tvOS apps do this, so I know it must be possible. I have been over the documentation carefully, but I must have missed something.
A related is issue is that the collectionView below won't take focus from the searchController. One has to go back using the remote menu button to get the collectionView to focus.
How can I get the searchController to appear as it does in the second screenshot when the view appears?
How can I get the collectionView to take focus from the searchController without having to go back to the tab bar?

is I finally ran across this passage in the tvOS developer library
All of the iOS first responder mechanisms work on tvOS. This allows
developers to present a UI, visible or hidden, and then make one of
the text fields the first responder by calling the
becomeFirstResponder method on it. This action causes the text field
to put up the keyboard UI without the user having to navigate to a
text field and click on it.
so, adding
searchController.searchBar.becomeFirstResponder()
displays the inline keyboard that I wanted users to start with. However, one has to press the menu button on the remote before the focus engine kicks in again. The menu button also dismisses the keyboard and searchBar returns to its button state.
This an answer to the first of my questions. Still clueless about the second.

Related

Big Sur Toolbar Items in the Sidebar

In Big Sur, Xcode and Calendar have toolbar items that stay over the sidebar when open but remain visible on the left side when the sidebar's collapsed.
Sidebar open:
Sidebar collapsed:
In "Adopt the New Look of macOS" at 13:55, John says "items placed before the separator [sidebarTrackingSeparator] will appear over the full-height sidebar", just as they are in Xcode and Calendar. I haven't been able to make this work.
Here's a sample project that demonstrates the issue. I used the IB-defined "Window Controller with Sidebar" and added a toolbar item for toggling the sidebar. In a subclass of NSWindowController I insert .sidebarTrackingSeparator after the .toggleSidebar item:
override func windowDidLoad() {
// Sometimes the toolbar items aren't loaded yet--async is a quick and dirty way to prevent a crash
DispatchQueue.main.async {
self.window?.toolbar?.insertItem(withItemIdentifier: .sidebarTrackingSeparator, at: 1)
}
}
Sometimes this has no effect (the toggle button remains to the right of the sidebar). Sometimes the sidebar toggle get put in an overflow menu:
I haven't seen any discussion of implementing this toolbar design outside that WWDC session. Has anyone been able to get this to work?
This is a IB/Code timing disagreement. Interface Builder configures and installs the toolbar before you add the .sidebarTrackingSeparator toolbar item.
So you're doing the right thing, just too late. And too later with the dispatch. I think the important thing is to have the item in there before the toolbar is set on the window.
Unfortunately, that isn't really possible with IB, unless I believe, you create a whole new toolbar and reassign it. But that's a bad idea, because then you may run into trouble auto-saving the state of your toolbar.
The trick is to configure the separator in Interface Builder. If you look at the ObjC documentation for this constant, you'll see a longer name: NSToolbarSidebarTrackingSeparatorItemIdentifier.
The best we can do here is hope that the symbol's name is the same value as the identifier. If you really want to verify this, you can just print the symbol's value in the debugger:
(lldb) po NSToolbarSidebarTrackingSeparatorItemIdentifier
NSToolbarSidebarTrackingSeparatorItemIdentifier
If we create a custom toolbar item in IB, and add that according to John's video...
low and behold:

NSTabView: Toolbar does not display

macOS 10.12.6; Xcode 9.3, storyboards
I have an NSTabView (tabless) that in itself contains two NSTabViews. One is tabless, the other one uses the 'toolbar' style.
When I start my app with the toolbar visible, everything is fine: it displays my tabs in the toolbar, I can change them, etc etc. Once I change to the other branch of my storyboard, the toolbar disappears... and when I come back, instead of a toolbar proper, with buttons and all that, I get a slightly widened bar that has no content in it.
I've set up a sample project to show my problem, where - for ease of switching - I have left the other two tabViewControllers to show their tabs (bottom/top, but this makes no difference).
1) First run (starting with 'toolbar' branch):
2) (not shown): switch to 'top' branch
3) After switching back to 'toolbar':
As a diagnostic aid, I've created a 'displayToolbarStatus' IBAction in the AppController:
#IBAction func displayToolbarStatus(_ sender: NSMenuItem){
if let window = NSApplication.shared.windows.first {
print(window.toolbar?.isVisible)
}
}
The results are as follows:
1) optional(true)
2) nil
3) optional(true)
which is very much in line with how things should work: the toolbar exists and is displayed, there is no toolbar, the toolbar exists and is displayed. Only, of course, it is not usable as a toolbar. (turning visibility off and on, or trying to force a size change with window.toolbar?.sizeMode = .regular has no effect whatsoever, nor does assigning icons to the toolbar items; the toolbar remains squashed and without functioning buttons.
I haven't worked in any depth with NSToolbar: is this a known problem with a workaround; is this new to Xcode 9.2 (which, after all, thinks that no window is valid, so obviously has some problems in that field)?
I really want to use the NSTabView 'toolbar' functionality: how do I proceed?
I've now had more time to play with toolbars. The 'weird' appearance of the non responsive toolbar is simply an empty toolbar, which gave me a clue as to what was going on.
0) The NSTabView overrides the window's toolbar; it does not hand back control when it vanishes; this means that if you have another toolbar in your window that will never show up the moment you're using an NSTabView with 'toolbar' style.
1) I have added a print statement to every relevant method in the ToolbarTabViewController and a 'Switching Tabs' in the containing TabViewController's DidSelect TabViewItem, as well as logging when Toolbar items are added to the window.
(The ToolbarTabViewController is the second controller in the containing TabViewController; it is selected. Otherwise the stack looks slightly different):
ViewDidLoad
Switching tabs
viewWillAppear
viewDidAppear
Switching tabs
Toolbar will add item
Toolbar will add item
viewWillAppear
viewDidAppear
Switching away to the other tab:
viewWillDisappear
Switching tabs
Toolbar did remove item
Toolbar did remove item
viewDidDisappear
So far, so good.
Switching back to the ToolbarTabController, we get
viewWillAppear
Switching tabs
viewDidAppear
Whatever method is called that adds the tabs-related items to the toolbar on first appearance does never get called again. (Note also that the the order of switching tabs and viewDidAppear is not consistent between the first and subsequent appearances.)
2) So, the logical thing to do seems to be to capture the items that are being created and to add them back for future iterations. In the ToolbarTabViewController:
var defaultToolbarItems: [NSToolbarItem] = []
#IBAction func addTabsBack(_ sender: Any){
if let window = NSApplication.shared.windows.first {
if let toolbar = window.toolbar{
for (index, item) in defaultToolbarItems.enumerated() {
toolbar.insertItem(withItemIdentifier: item.itemIdentifier, at: index)
}
}
}
}
override func toolbarWillAddItem(_ notification: Notification) {
// print("Toolbar will add item")
if let toolbarItem = notification.userInfo?["item"] as? NSToolbarItem {
if defaultToolbarItems.count < tabView.numberOfTabViewItems{
defaultToolbarItems.append(toolbarItem)
}
}
}
3) The last question was when (and where) to call addTabsBack() - I found that if I try to call it in viewWillAppear I start out with four toolbarItems, though the number of tabViewItems is 2. (and they do, in fact, seem to be duplications: same name, same functionality). Therefore, I am calling addTabsBack()in the surrounding TabViewController's 'didSelect TabViewItem' method - willSelect is too early; but didSelect gives me exactly the functionality I need.
4) There probably is a more elegant way of capturing the active toolbarItems, but for now, I have a working solution.

NSPopover closes automatically

I have a xib with my view and an NSPopover with Transient behavior:
In the view controller, I have an action to control the popover like this:
#IBAction func moreClicked(sender: NSButton) {
if !moreOpen {
moreOpen = true
scriptsPopover.showRelativeToRect(sender.bounds, ofView: sender, preferredEdge: 2)
} else {
moreOpen = false
scriptsPopover.close()
}
}
When I click my button the popover appears as expected. But after 5 seconds it disappears.
I want the popover to present a number of buttons and only disappear when the user clicks one of those buttons or clicks elsewhere in the UI. Like the Autolayout Pin button in Interface Builder to mention an example.
I tried defining the behavior as Transient, Semi-transient, Application-defined. All have exactly the same result: It dismisses itself after a few seconds.
I tried implementing the popoverShouldClose delegate and returning false to let me control it. It does block the close, but when the user clicks the button to close, it just opens a new popover on top of the old. The popover also loses its arrow after I return false from popoverShouldClose, which looks weird.
Here's a recording of the annoying automatic close
See the stack trace when the popoverShouldClose method is called. You'll see the cause of this in that stack trace, and from there, try to eliminate this cause.
What I'm suspecting is that your popover is being deallocated as it isn't being strongly held by you.

SWIFT: How to display activity indicator when user clicks on Tab Bar

I'm trying to add an activity indicator when a user clicks on my tab bar menu but it seems complicated actually.
I have 4 tab bar items and they parse a json from an URL. My problem is when the user clicks on tab bar item and the screen just freezes before show the next view. I would like to change to the view and then show an activity indicator while they make the url petition and parse the item.
I have one class that conform the UITabBarController method, but I'm reading some exemples in Objective-C that they talk about UITabBarDelegate.
How can I try to solve this? I really appreciate your help, thanks!

IPad Textfield DropDown with PopOver Control

Im wanting to create a generic dropdown control for my IPad app. Basically when the user clicks on a textfield a popover control will show and list items. The users can keep typing in the textfield which will filter the items in the dropdown popover control.
Has anyone got any advice or know of any examples on accomplishing this?
Basically it will be like the "Suggestions" popover list in the App store search field of the ipad.
Thanks in advance
Well, I would accomplish this by loading a TableViewController into the PopoverController and make its interface available to the ViewController (the one that has the textfield in it).
In the TableViewController I would load a dictionary/array of items. Whenever a user enters text in the textfield (you can respond on this trough events in your Interface Builder) I would then call a function in the TableViewController that updates the list that is displayed (e.g. displays all dictionary items that start with the entered text).
Whenever someone clicks on a item in TableViewController, you can then call a function in the ViewController.
I can't give you a code sample, since that would require quite some time to create :P.
I hope this helps you.

Resources