Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I working with swift 4 for osx and I would like to realize a address autocomplete function like apple maps does:
How can I do something like the image shows?
I guess the structure will be:
a simple NSTextfield
but what is the popup menu? is it a simple popover?
UPDATE
Now my app works like this:
Thats brilliant.
But one little problem:
I write my first character into the textfield, the popover will be shown and the textfield lost the focus. Now I have to click again in my textfield to go on. Is there a way to keep the focus of this textfield?
I ported the Apple "CustomMenus" example from Objective-C to Swift. The example includes a search completions dropdown menu for NSSearchField:
https://github.com/dougzilla32/CustomMenus
Original example on the Apple site in Objective-C:
https://developer.apple.com/library/content/samplecode/CustomMenus
i solve the situation like this:
use the controlTextDidChange and present a popover
override func controlTextDidChange(_ obj: Notification) {
vcAddress.searchString = txtSourceAddress.stringValue
self.presentViewController(vcAddress, asPopoverRelativeTo: txtSourceAddress.bounds, of: txtSourceAddress, preferredEdge: .maxX, behavior: .semitransient)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "AutoComplete"), object: nil)
}
the popover has a tableview, which gets the suggestions with the SearchCompleter (MapKit)
import Cocoa
import MapKit
class AcAddress: NSViewController, NSTableViewDelegate, NSTableViewDataSource, MKLocalSearchCompleterDelegate {
var searchString:String?
var searchCompleter = MKLocalSearchCompleter()
var searchResults = [MKLocalSearchCompletion]()
#IBOutlet weak var tblAutoComplete: NSTableView!
override func viewDidLoad() {
NotificationCenter.default.addObserver(self, selector: #selector(AutoComplete), name: NSNotification.Name(rawValue: "AutoComplete"), object: nil)
searchCompleter.delegate = self
tblAutoComplete.refusesFirstResponder = true
}
#objc func notificationAutoComplete() {
searchCompleter.queryFragment = searchString ?? ""
}
func completerDidUpdateResults(_ completer: MKLocalSearchCompleter) {
searchResults = completer.results
tblAutoComplete.reloadData()
}
func numberOfRows(in tableView: NSTableView) -> Int {
return searchResults.count
}
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
// FILL IT
}
}
Related
I have a MKMapView in one of my static cells. Instead of being able move the map around, I would like the user to be able to tap the map and have it expand full screen. Then within the full screen the user can move around and zoom in and out. They will eventually be able to see where I have pins placed based on other users' city where they are located.
I am getting an error when the map is tapped.
Thread 1: "-[HomeTableViewController triggerTouchAction:]: unrecognized selector sent to instance 0x115e2f8a0"
Here is the important code for the map and touch gesture for the controller:
import UIKit
import CoreLocation
import MapKit
class HomeTableViewController: UITableViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Always adopt a light interface style.
overrideUserInterfaceStyle = .light
let gestureRecognizer = UITapGestureRecognizer(target: self, action:"triggerTouchAction:")
mapView.addGestureRecognizer(gestureRecognizer)
}
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 7
}
func triggerTouchAction(gestureReconizer: UITapGestureRecognizer) {
//Add alert to show it works
print("Map Tapped")
}
}
I would love to be able to move forward with this part of my app. Thank you in advance for helping me out. I am very new to coding and wish I had gotten my degree in it.
I am unable to populate a swift cell-based tableview in macOS 10.14.6 using an Xcode 11.2 xib. The app is Document based and the tableView is created with a separate WindowController xib. A similar project created programmatically in Xcode works ok, including drag and drop; I am relatively new to using xibs and likely have not set things correctly. A column identifier has been set in the xib and NSTableViewDataSource and NSTableViewDelegate have been added to the Window Controller. Pertinent source code follows and the complete Xcode project may be downloaded here: https://www.dropbox.com/s/6tsb98b7iihhfxl/tableView.zip?dl=0
Any help in getting the tableView populated with a String array would be appreciated. I would also like to get drag and drop working but can get by for now just getting the array items to show up in the table view. It correctly creates four rows, corresponding to the number of elements in the array, but there is no visible text. The tableView is cell-based, but I could use view-based if that would work better. Thank you in advance.
class WindowController: NSWindowController, NSTableViewDataSource, NSTableViewDelegate {
#IBOutlet var tableView: NSTableView!
var sports : [String] = ["Basketball","Baseball","Football","Tennis"]
override func windowDidLoad() {
super.windowDidLoad()
tableView.registerForDraggedTypes([NSPasteboard.PasteboardType.fileURL])
tableView.dataSource = self
tableView.delegate = self
}
func numberOfRows(in tableView: NSTableView) -> Int {
return (sports.count)
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
var value : Any? = 0
let columnIdentifier : String = (tableColumn?.identifier.rawValue)!
if (columnIdentifier == "Col1"){
value = sports[row]
}
return value
}
In Document.swift windowController is released at the end of showTableView() and the table view looses its data source. Add windowController to the window controllers of the document or hold a strong reference to windowController.
#IBAction func showTableView(_ sender: Any) {
let windowController = WindowController.init(windowNibName:NSNib.Name("WindowController"))
addWindowController(windowController)
windowController.showWindow(nil)
}
I want to include a view-based NSTableView in the popover of a Safari App Extension.
Starting with the default project in Xcode, I made the SFSafariExtensionViewController the delegate and datasource for the table view as it is the only content on the popover, and mostly this works.
I can populate the table and implement methods like tableView(_:shouldSelectRow:), yet methods which return a notification object such as tableViewSelectionDidChange(_:) do not get called.
Whilst those methods show a cludgy way of knowing when a row is selected, I am left with no way of knowing when a cell is edited.
As I had to connect the delegate outlet of the NSTableView to the File Owner to allow the delegated methods to work, I also tried connecting the dataSource outlet too, but this rightly did not help.
Here is the essence of my code (which for now includes returning dummy table data to test editing):
class SafariExtensionViewController: SFSafariExtensionViewController {
#IBOutlet weak var tableView: NSTableView!
static let shared: SafariExtensionViewController = {
let shared = SafariExtensionViewController()
shared.preferredContentSize = NSSize(width:445, height:421)
return shared
}()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
}
func textDidEndEditing(_ notification: Notification) {
NSLog("I will NEVER appear in the console")
}
}
extension SafariExtensionViewController: NSTableViewDataSource {
func numberOfRows(in tableView: NSTableView) -> Int {
return 5
}
}
extension SafariExtensionViewController: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cellView = tableView.makeView(withIdentifier: tableColumn!.identifier, owner: self) as? NSTableCellView
cellView?.textField?.stringValue = "Blah"
return cellView
}
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
NSLog("I will appear in the console")
return true
}
func tableViewSelectionDidChange(_ notification: Notification) {
NSLog("I will NEVER appear in the console")
}
func controlTextDidEndEditing(_ obj: Notification) {
NSLog("I will NEVER appear in the console")
}
}
(Obviously I do not need both textDidEndEditing(_:) and controlTextDidEndEditing(_:) but I am just trying everything.)
I am guessing the problem is something to do with the table view not being registered for notifications within a SFSafariExtensionViewController? That object inherits from NSViewController, though, so I would have thought these methods should work automatically.
This is my first time using swift, and it is a long time since I wrote a Mac app. But the actual functionality of the extension works, now I just want to have the ability to customize the settings through the UI.
However there seems to be very little written about Safari app extension programming, Apple's documentation is sparse, and I have not even been able to find any code examples featuring a table view in a popover to learn from.
I am probably missing something very obvious, but I have run out of searches to try on here and the web in general, so any help will be appreciated.
UPDATE:
I think I have an answer, by explicitly linking the NSTextFields in the table to the File's Owner as a delegate, the tableViewSelectionDidChange(_:) and controlTextDidEndEditing(_:) methods are now working. There must have been something else wrong causing the former to not work that I accidentally broke and fix, but it makes some sense for the latter.
That is all I need for the functionality to work, however I am still confused why the textDidEndEditing(_:) is still not working when I am led believe it should.
And in Apple's documentation, textDidEndEditing(_ :) is a method of an NSTextField, which links to a page saying controlTextDidEndEditing(_ :) is deprecated
And I misunderstanding anything?
I think you are not setting up the outlet properly please confirm this. Also check you setting up reusable identifier? identifier. for me all delegate calling without no issue after that.
I am extremely new to Swift so I am guessing this is a rookie mistake but here's my situation:
I am trying to create an application that allows you to add things to a list. I have a NSTextField where users input there data and a NSButton to add that data to the myTeam array. The tableView is binded (I think that's what you call it) to the myTeam array.
When I run the application a table containing the preset values of myTeam populate the table view correctly, but when I add to this array nothing happens. After research, I found this question.
Unfortunately, like most swift tutorials and Q&A, it was for iOS. But I thought I would give it a try. I added
self.tableView.reloadData()
self.refresher.endRefreshing()
to my code, and received two errors: Value of type '(NSTableView, NSTableColumn?, Int) -> Any?' has no member 'reloadData' and Value of type 'ViewController' has no member 'refresher', respectively.
Heres my code below:
import Cocoa
import Darwin
class ViewController: NSViewController, NSTableViewDataSource {
var myTeam = ["Test", "Test2"]
#IBOutlet weak var myText: NSTextField!
#IBOutlet weak var AddMember: NSButton!
#IBAction func addmem(_ sender: Any) {
myTeam.append(myText.stringValue);
self.tableView.reloadData()
self.refresher.endRefreshing()
}
override func viewDidLoad() {
super.viewDidLoad()
}
override var representedObject: Any? {
didSet {
// Update the view, if already loaded.
}
}
// MARK: DataSource
func numberOfRows(in tableView: NSTableView) -> Int {
return myTeam.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return myTeam[row]
}
}
P.S. I used this tutorial to get as far as I did.
Simplest solution, we are going to use (full) Cocoa Bindings:
Replace the entire code with
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var myText: NSTextField!
#objc dynamic var myTeam = ["Test", "Test2"]
#IBAction func addmem(_ sender: NSButton) {
myTeam.append(myText.stringValue)
}
}
In Interface Builder select the table view (not the enclosing scroll view) and press ⌥⌘6 (Connections Inspector)
Disconnect dataSource
Press ⌥⌘7 (Bindings Inspector)
Bind Content to ViewController > Model Key Path myTeam
Since you are still using objectValueFor I assume that the value of the table cell view is already bound to objectValue.
macOS doesn't know a refresher.
I have an OS X application written in Swift (thanks to Mathias and Gallagher) that uses a cell-based NSTableView. One of the requirements by the client was to be able to increase the font size of the text displayed in each text field cell. It all seemed pretty straight forward after a bit of stack overflow googling: set each NSTableView column’s dataCell font to the desired font and size; then subclass the NSTextFieldCell and override the drawInteriorWithFrame and titleRectForBounds and adjust the height to fit the rect.
However, since Apple has depreciated cell-based NSTableViews in favor of view-based I figured I should change my code to view-based.
Argh! What seemed like such a simple change has caused me two days of hair pulling grief. I can get the text font size to change just fine but the NSTextFieldCell NSRect height stays fixed. What few examples I’ve seen on the web are for iOS and don’t work for OS X.
Is there an easy way to do this?
I marked your question as favorite, tried it, failed, and slept on it for a long time. But I think I've solved it for all future Googlers.
You shouldn't have to subclass anything for this. Try this:
In Interface Builder:
Select the Table View Cell (#1 in the screenshot), open the Identity Inspector (Cmd + Opt + 3) and set its Identifier to myTableViewCell
Select the Text Cell (#2 in the screenshot), open the File Inspector (Cmd + Opt + 1) and uncheck Use Auto Layout
In your view controller:
Connect the outlets and actions and you should be fine:
class AppDelegate: NSObject, NSApplicationDelegate, NSTableViewDataSource, NSTableViewDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var tableView: NSTableView!
var names = ["Luke Skywalker", "Han Solo", "Chewbecca"]
var fontSize = NSFont.systemFontSize()
func applicationDidFinishLaunching(aNotification: NSNotification) {
self.tableView.setDataSource(self)
self.tableView.setDelegate(self)
}
func numberOfRowsInTableView(tableView: NSTableView) -> Int {
return self.names.count
}
func tableView(tableView: NSTableView, viewForTableColumn tableColumn: NSTableColumn?, row: Int) -> NSView? {
let cellView = tableView.makeViewWithIdentifier("myTableViewCell", owner: self) as! NSTableCellView
let textField = cellView.textField!
let fontDescriptor = textField.font!.fontDescriptor
textField.font = NSFont(descriptor: fontDescriptor, size: self.fontSize)
textField.stringValue = self.names[row]
textField.sizeToFit()
textField.setFrameOrigin(NSZeroPoint)
tableView.rowHeight = textField.frame.height + 2
return cellView
}
#IBAction func makeBigger(sender: AnyObject) {
self.fontSize += 1
self.tableView.reloadData()
}
#IBAction func makeSmaller(sender: AnyObject) {
self.fontSize -= 1
self.tableView.reloadData()
}
}