I'm building my macOS app that contains NSPopover with NSTextView inside. If "Look up & data detectors" is active at system preferences, NSTextView will support this functionality without any additional settings. But in case, when you place NSTextView inside of NSPopover, this function won't work anymore. Is there any way to fix this problem without NSTextView.showDefenition(for: at:)?
How it usually works
Same thing, but won't work with NSTextView that placed inside of NSPopover
I've started new test project just to check behaviour, so code is simple as it is.
Main Controller:
import Cocoa
class ViewController: NSViewController {
#IBOutlet weak var popoverButton: NSButton!
#IBAction func pressButton(_ sender: NSButton) {
let popover = NSPopover()
popover.contentViewController = PopoverController()
popover.contentSize = CGSize(width: 470, height: 300)
popover.show(relativeTo: popoverButton.bounds, of: popoverButton, preferredEdge: NSRectEdge.minY)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
Popover Controller:
import Cocoa
class PopoverController: NSViewController {
var textView = NSTextView()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear() {
super.viewWillAppear()
view.addSubview(textView)
textView.translatesAutoresizingMaskIntoConstraints = false
textView.frame = view.bounds
}
}
Related
I'm trying to create a "Global View" maybe it goes into AppDelegate, but I'm not sure. I would like my View to always be visible, no matter what ViewController .xib you are on in the app.
For now I have inserted the View in the first ViewController .xib but when I navigate in the other ViewControllers the View disappears.
This is the code:
import UIKit
class MonitoringViewController: UIViewController {
#IBOutlet var contentView: UIView!
#IBOutlet weak var viewForTab: UIView!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttonTab1(_ sender: UIButton) {
}
#IBAction func buttonTab2(_ sender: UIButton) {
delegate?.navigateToAlertViewController()
let alert = AlertViewController(nibName: "AlertViewController", bundle: nil)
contentView.addSubview(alert.view)
alert.didMove(toParent: self)
}
#IBAction func buttonTab3(_ sender: UIButton) {
}
}
I need to show containerview in viewcontroller, so i have taken one viewcontroller and designed and in that i have taken one containerview below to the buttons view
given containerview constraints: below to the buttonview
top = buttonview.bottom 10, leading, trailing, bottom = 0
there are two buttons indicates with green line.. initially i am in the "viewproposalvc" with red colour button.. here if i click gray colour button then i need to show containerview
here the viewproposalvc code:
class ViewProposalVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var postId: Int?
#IBOutlet weak var containerView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
updateNavigationBar(with: "View Proposal")
containerView.isHidden = true
}
#IBAction func grayBtn(_ sender: Any) {
containerView.isHidden = false
let vc = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ContainerVC") as? ContainerVC
vc.serviceId = self.viewproposalData?.result?.posted_services?.id
self.navigationController?.pushViewController(vc!, animated: true)
}
#IBAction func redBtn(_ sender: Any) {
containerView.isHidden = true
postedServicesCall()
}
}
this is containervc code:
class ContainerVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
override func viewDidLoad() {
super.viewDidLoad()
}
}
but here containervc not coming below to the buttonsview.. its coming in separate viewcontroller, why?
o/p of containervc: i dont want separate viewcontroller.. i need containervc to show below to the buttonsview of the viewproposalvc
first time i am working with container views, please do help
The reason why is because you are calling
self.navigationController?.pushViewController(vc!, animated: true)
ContainerView is just a generic UIView with an embedded segue, that is triggered from viewDidLoad of the hosted VC. If you need to do additional setup of that VC I suggest making an var on ViewProposalVC and making desired changes from there.
as in
class ViewProposalVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
var postId: Int?
#IBOutlet weak var containerView: UIView!
#IBOutlet weak var secondaryController: UIViewController!
override func viewDidLoad() {
super.viewDidLoad()
updateNavigationBar(with: "View Proposal")
containerView.isHidden = true
}
#IBAction func grayBtn(_ sender: Any) {
containerView.isHidden = false
self.secondaryController.serviceId = self.viewproposalData?.result?.posted_services?.id
}
I'm doing a test of a custom keyboard. This is what I need:
It has to have two UITextFields. Cannot be labels.
The keyboard is an embedded UIView.
The default keyboard should be disabled.
It cannot be a keyboard extension.
Not sure why the app is crashing. PS: Not all the keys are on the code yet. Here is an image of what I'm trying to do and the two View Controllers.
Edit: The error is: Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
First ViewController:
import UIKit
class HomeVC: UIViewController, ButtonTapDelegate {
#IBOutlet var textField1: UITextField!
#IBOutlet var textField2: UITextField!
#IBOutlet var keyboardView: UIView!
var buttonPressed = [String]()
override func viewDidLoad() {
addKeyboard(view: keyboardView)
buttonPressed = [String]()
textField1.inputView = UIView()
textField2.inputView = UIView()
}
func addKeyboard(view: UIView) {
let keyboard = KeyboardVC(nibName: "KeyboardVC", bundle: nil)
view.addSubview(keyboard.view)
addChild(keyboard)
}
func didTapButton(sender: UIButton) {
if sender.tag == 5 {
textField1.text?.append(contentsOf: " ")
} else if sender.tag == 6 {
textField1.text?.removeAll()
buttonPressed = [String]()
} else {
let val = sender.titleLabel?.text
textField1.text?.append(contentsOf: val!)
}
self.textField1.text = buttonPressed.joined(separator: "")
}
}
Here is the second View Controller:
import UIKit
protocol ButtonTapDelegate {
func didTapButton(sender: UIButton)
}
class KeyboardVC: UIViewController {
var delegate: ButtonTapDelegate!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func buttons(_ sender: UIButton) {
delegate.didTapButton(sender: sender)
print(sender)
}
}
var delegate: ButtonTapDelegate!
An implicitly unwrapped optional is essentially a promise that you're definitely going to give the variable a value before you try to access it. The problem in this case is that you haven't done that. Most likely, you want to do this in your first view controller:
func addKeyboard(view: UIView) {
let keyboard = KeyboardVC(nibName: "KeyboardVC", bundle: nil)
keyboard.delegate = self // Now "delegate" will have a value before the function gets called
view.addSubview(keyboard.view)
addChild(keyboard)
}
I have a NSMenu with a custom views, just like this.
ViewController.swift
class ViewController: NSViewController {
#IBOutlet var theMenu: NSMenu!
#IBOutlet var theMenuItem: NSMenuItem!
#IBOutlet var customView: NSView!
override func viewDidLoad() {
theMenuItem.view = customView
}
#IBAction func showTheMenuWithCustomView(_ sender: NSButton) {
// Popup the menu below button
let position = NSPoint(x: 0, y: sender.frame.height+2)
theMenu.popUp(positioning: nil, at: position, in: sender)
}
}
This works well.
But in custom views, i need to popup an another menu. After i call the popUp method, it just show nothing. Here is the code:
CustomView.swift
class CustomView: NSView {
#IBAction func showCustomViewMenu(_ sender: NSButton) {
// Create the menu in custom view
let customViewMenu = NSMenu()
// Add a menu item in it
customViewMenu.addItem(withTitle: "no one care", action: nil, keyEquivalent: "")
// Popup the menu below button
let position = NSPoint(x: 0, y: sender.frame.height+2)
customViewMenu.popUp(positioning: nil, at: position, in: sender)
}
}
You can clone this project to test it:
https://github.com/Caldis/NSMenuQuestion
How can i Popup NSMenu in custom views in NSMenuItems ?
Use this line to show the additional popup on CustomView:
NSMenu.popUpContextMenu(customViewMenu, with: NSApp.currentEvent!, for: sender)
Additionally, if you also need to disable other popups on whole CustomView, override rightMouseDown in CustomView, like so:
class CustomView: NSView {
override func rightMouseDown(with event: NSEvent) {
// Do nothing
}
}
I am currently writing an OS X application using Swift 2. I am wanting to build the UI without XIBs or Storyboards. The problem I am having is on initializing a custom ViewController that I can put my views in.
Here is my AppDelegate:
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
var viewController: MyViewController?
func applicationDidFinishLaunching(aNotification: NSNotification) {
viewController = MyViewController()
self.window.contentView!.addSubview(viewController!.view)
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
And MyViewController:
class MyViewController: NSViewController {
var textField: NSTextField?
override func viewDidLoad() {
super.viewDidLoad()
textField = NSTextField(frame: NSRect(x: 10, y: 10, width: 100, height: 100))
textField!.bezeled = false
textField!.drawsBackground = false
textField!.editable = false
textField!.selectable = false
textField!.stringValue = "TEST"
self.view.addSubview(textField!)
}
}
The problem is that when I add the viewController's view as a subview of the window's contentView, I get the following error and the view doesn't load.
2015-12-06 17:34:18.204 Test[9682:1871784] -[NSNib
_initWithNibNamed:bundle:options:] could not load the nibName:
Test.MyViewController in bundle (null).
I'm not sure what I'm doing wrong - any help would be appreciated.
From the NSViewController documentation:
If you pass in a nil for nibNameOrNil then nibName will return nil and
loadView will throw an exception; in this case you must invoke
setView: before view is invoked, or override loadView.
The initializer for MyViewController() uses nil for the nibName.
Two potential fixes:
1. Set the view in your AppDelegate
func applicationDidFinishLaunching(aNotification: NSNotification) {
viewController = MyViewController()
viewController!.view = NSView() // added this line; edit to set any view of your choice
self.window.contentView!.addSubview(viewController!.view)
}
Alternately,
2. Override loadView in your subclassed ViewController
import Cocoa
class MyViewController: NSViewController {
var textField: NSTextField?
override func loadView() {
self.view = NSView() // any view of your choice
}
override func viewDidLoad() {
super.viewDidLoad()
textField = NSTextField(frame: NSRect(x: 10, y: 10, width: 100, height: 100))
textField!.bezeled = false
textField!.drawsBackground = false
textField!.editable = false
textField!.selectable = false
textField!.stringValue = "TEST"
self.view.addSubview(textField!)
}
}