I am facing a strange behavior of NSCollectionView inside a NSTabViewController.
I think that this issue appeared when I upgraded to High Sierra (not sure though).
My app has four tabs and each of them contains a collection view:
When I launch the app, the first tab is fine, problem is when I switch to other tabs. The collection view is not properly laid out:
As soon as I touch the window border the collection view reorganizes normally.
I tried to force the collection view to layout (.collectionView.layout()) without success.
Can anyone help me?
Thank you
This helped me out:
Subclassed the NSTabViewController
Added this:
override func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) {
let controller = tabViewItem?.viewController as? MyController
controller?.collectionView.frame = (controller?.view.frame)!
}
I ran into the same problem recently and the provided fix didn't work with my particular subview layout, but this did:
override func tabView(_ tabView: NSTabView, didSelect tabViewItem: NSTabViewItem?) {
if let controller = tabViewItem?.viewController as? MyController,
let collectionView = controller.collectionView,
let contentSize = collectionView.collectionViewLayout?.collectionViewContentSize,
contentSize.height > collectionView.frame.size.height
{
collectionView.frame.size.height = contentSize.height
}
}
Maybe this is a more generally applicable solution.
Related
In iOS 13 the behavior has changed so that by default when Navigation controller appears the search bar is visible (when UISearchController is assigned to a navigationItem.searchController). Some system apps appear with the search bar hidden (you need to swipe down for it to appear), but I don't see any specific property that would allow this. How to achieve this - maybe there is some property or some method to do that?
Via experimentation, I have discovered that if you delay assigning the search controller to the navigation item until viewWillLayoutSubviews or viewDidLayoutSubviews, the search controller starts out hidden, as desired. However, this if you do this on iOS 12 or earlier, the search controller will not be revealed when scrolling down.
I ended up doing the following with a messy version check, which is working for me:
override func viewDidLoad() {
super.viewDidLoad()
searchController = /* make search controller... */
if #available(iOS 13, *) {
// Attaching the search controller at this time on iOS 13 results in the
// search bar being initially visible, so assign it later
}
else {
navigationItem.searchController = searchController
}
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
navigationItem.searchController = searchController
}
To start with a hidden searchBar, simply set the navigationItem.searchController property after your table view (or collection view) has been populated with data.
Inspired by bunnyhero's answer I put the code responsible for setting the UISearchController in navigationItem inside the viewDidAppear method. Seems to be working every time for me on iOS 14/15
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if navigationItem.searchController == nil {
navigationItem.searchController = searchController
}
}
Edit: I was overly optimistic. On iOS 15.2 this method stopped working for me. What I did to fix it was to move the code after reloading my table/collection view.
I find this works:
self.searchController.searchBar.hidden = YES;
You will need to unhide at the appropriate time.
I managed to make this work by setting isTransculent false on the navigationBar and having initial data on UITableView or UICollectionView. If you have 0 cells initially and trigger reloadData after some time (maybe a network call), SearchBar is visible initially. So have a dummy cell or something similar initially and load the data later, if that's the case for you.
navigationController?.navigationBar.isTranslucent = false
One should set searchController after tableView gets frame
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
super.scrollViewDidScroll(scrollView)
if !scrollView.frame.isEmpty, navigationItem.searchController == nil {
navigationItem.searchController = searchController
}
}
This is what works for me. I have a UISegmentedControl that reloads the tableView when filter changes.
With FRC:
guard let count = try? fetchedResultsController.managedObjectContext.count(for: request) else { return }
called after tableView.reloadData()
navigationItem.searchController = count > 20 ? searchController : nil
Swift 5.2 & iOS 13.3.1:-
Try like this. It works fine
navigationItem.hidesSearchBarWhenScrolling = false
I'm trying to find how to bring up a second view/window after pushing a button on my primary window. I have read about segues and I can get the first window to display the second but the second is not connected to a view controller so I can't add any code to any controls on the second view. Try as I might I cannot create a SecondViewController.swift file and connect it to a window controller or a view controller. The tutorials I have found all deal with iOS and I want OS X which means there are just enough differences to keep me from figuring this out.
Can anyone show me how to do this?
Ta,
A.
First make new file like:
After that, put these codes in your classes and that should do it.
class SecondWindowController: NSWindowController {
convenience init() {
self.init(windowNibName: "SecondWindowController")
}
}
class ViewController: NSViewController {
private var secondWindowController: SecondWindowController?
#IBAction func showSecondWindow(sender: AnyObject) {
if secondWindowController == nil {
secondWindowController = SecondWindowController()
}
secondWindowController?.showWindow(self)
}
}
I am trying to add an outlet into my viewcontroller for a toolbar item in my window controller. I have tried playing around with first responder and bindings but have not been able to find any solutions.
A similar question that was answered provided some insight but no one has mentioned anything about IBOutlets other than still asking how to add them in the comments. The answer has been accepted so i am assuming no one will add to it.
How to use NSToolBar in Xcode 6 and Storyboard?
Incase my question is unclear at all, i would like to be able to add this to my storyboard program
#IBOutlet weak var Mytoolbar: NSToolbarItem!
func enabletoolbar()
{
Mytoolbar.action = "FunctionIn.ViewController.swift"
Mytoolbar.enabled = true
}
I found a decent workaround by adding IBOutlets to my custom NSWindow class and using the storyboard to connect my views to the IBOutlets. Then, I accessed these views from my NSViewController class by getting them from the custom NSWindow.
Basically you need to set the action and other properties to the toolbaritem but not in the toolbar. So try the same.
i ended up doing this in my view controller which seems to work
override func viewDidLayout() {
var x = self.view.window?.toolbar?.items[1].label
println(x)
if(self.view.window?.toolbar?.items[0].label! != "Check")
{
toobarediting()
}
println("didlay")
}
func toobarediting() {
self.view.window?.toolbar?.insertItemWithItemIdentifier("Check", atIndex: 0)
}
func toolbarcheck(functiontoset: Selector) {
var y = self.view.window?.toolbar?.items[0] as NSToolbarItem
y.action = functiontoset
if(functiontoset != nil)
{
y.enabled = true
}
}
It seems to allow me to make the tool bar button clickable/unclickable when ever i require it to change it just seems so much more bulky and error prone than
myitem.enable = fale
myitem.action = nil
is this really the best way for a storyboard based application in osx?
While connectiong IBActions works by using either the First Responder or by adding an "Object" to the scene, then changing its class to the window's view controller class, this doesn't help with IBOutlets and delegates that you'd like to point to the view controller.
Here's a work-around for that:
Add the Toolbar to the View Controller, not to its Window. That way, you can make all the IBOutlet connections in the View Controller Scene easily. I've done that for years and found no issues with it, even when using Tabs.
You'll have to assign the window's toolbar in code, then. E.g. like this:
#interface ViewController ()
#property (weak) IBOutlet NSToolbar *toolbar; // connect this in your storyboard to the Toolbar that you moved to the View Controller Scene
#end
- (void)viewWillAppear {
[super viewWillAppear];
self.view.window.toolbar = self.toolbar;
}
I'm trying to add a new sub view form a nib using swift for OS X.
So far i've:
created a new "Cocoa Application"
added a new "Cocoa Class" called "TestSubView" as a subclass of NSViewController with a XIB file
I want to add this subview to my main view when the application loads.
in my ViewController ( the ViewController for the main window ) i have.
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let newSubView = TestSubView();
self.view.addSubview(newSubView.view);
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
But i'm getting the following error
Failed to set (contentViewController) user defined inspected property on (NSWindow):
-[NSNib initWithNibNamed:bundle:] could not load the nibName: temp.TestSubView in bundle (null).
I realise i will need to size and position this subview but I can't seem to get to that point.
I've spent the better part of a day trying to figure this one out so any help would be greatly appreciated.
I finally got this thing to work. My new code looks like
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
let subview = TestSubView(nibName: "TestSubView", bundle: nil)!
self.view.addSubview(subview.view)
}
override var representedObject: AnyObject? {
didSet {
// Update the view, if already loaded.
}
}
}
Found with the help of the docs & this answer
It was suggested that if the nib name and the class name are the same you shouldn't need to declare nibname: (as i'd tried to do originally) but the docs didn't mention this - explains why it didn't work!
For prosperity, this worked for me with Xcode 6.1.1 on OS X Yosemite (10.10.1)
A nib is really nothing but an XML file with view information in it. You have to get it from the application bundle and get one of the views contained in it explicitly. You are perhaps confounding views and view controllers (your attempt to extract view from newSubView suggests that).
Try this:
let subview = NSBundle.mainBundle().loadNibNamed("TestSubView",
owner:self, options:nil)![0]! // maybe no final unwrapping "!" in Swift 3
self.view.addSubview(subview)
Make sure the xib is really called the name you are using and contains at a least one view (otherwise the two unwrapping ! above will crash your app).
I try to make simple OSX application with WebView. I am new in Swift, and have some errors:
it's my WebView delegate file:
class WebViewControllerDelegate: NSObject{
#IBOutlet var webview: WebView!
override init()
{
super.init()
self.webview.frameLoadDelegate = self
let url = NSURL(string: "http://google.com")
let request = NSURLRequest(URL: url);
self.webview.mainFrame.loadRequest(request)
}
func didFinishLoadForFrame()
{
println("ok:")
}
}
I try to run this, but have EXC_BAD_INSTRUCTION error at line where I set frameLoadDelegate to self. I think it's error with web view outlet, but i can't fix it.
self.webview is nil, and i don't know why...
Views in Xib / Storyboard files are not loaded nor connected during initialization. That is why self.webview is nil in your code.
You really should not attach the IBOutlet directly to your "delegate". Instead, connect it to your view controller and have the view controller set it on the delegate. You should do that in viewDidLoad because that is when you can guarantee all of the objects have been created and connected.
I had same error before. I give you a suggestion for solve this error. Do following things...
1. Click on the View Controller open the connection inspector.
See this...
2. And then you have to double check on the connection inspector window and find something contain like following image...
3. Then you have to delete one outlet. According to my one I have to delete below one... finally solved one...
Then run the code...