I´m working on an app with Apple's PDFKit and have managed to put some Annotation-Buttons with a working PDFActionURL, which open the iOS standard browser after tapping on them.
Unfortunately, I did not find a working solution, how to open the associated links in an In-App-Browser or to load it in a webview. After tapping the AnnotationButton PDFKit automatically opens Safari and I haven´t found a property or another way concerning iOS to influence this behavior by manipulating f.e. the PDFAction.
let urlString = "https://www.apple.com"
let urlAction = PDFActionURL(url: urlString)
urlButton.action = urlAction
pdfPage.addAnnotation(urlButton)
Is there a way to force the call of an In-App-Browser at every UIApplication.shared.open() or to manipulate the execution of a PDFAction?
Finally, I figured it out for myself ;) I´ve overlooked one function of the PDFViewDelegate
By setting the delegate of the pdfView to the involved ViewController and using this function
func pdfViewWillClick(onLink sender: PDFView, with url: URL) {
print(url)
}
you are able to use the associated URL of the PDFActionButton and to trigger an In-App-Browser (e.g. SFViewController).
You want to instantiate the view like so:
let webV:UIWebView = UIWebView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height))
webV.loadRequest(NSURLRequest(URL: NSURL(string: "http://www.google.co.in")))
webV.delegate = self;
self.view.addSubview(webV)
Found HERE
To do it right, I would create a new ViewController in your storyboard, nested in a navigationController and segue to the view on annotation selection. Display your content on viewDidLoad using a similar set of code as seen above. That code is probably in an older version of swift so you'll need to update it. There is more detail about using the delegate associated in the link provided.
Related
I'm migrating my macOS app built with SwiftUI 1 to SwiftUI 2. There is a feature that allows user to save the main view as pdf using NSPrinterOperation, which takes an NSView instance.
Currently, the app is on SwiftUI 1 with AppDelegate, and I can get the main view through this code
Button("Print") {
let appDelegate = NSApp.delegate as! AppDelegate
let view = appDelegate.window.contentView! // returns the NSHostingView set up in AppDelegate.swift
...
NSPrintOperation(view: view, printInfo: newInfo).run()
}
Since upgrading to SwiftUI2, the AppDelegate is no longer there, and how can I get the view now?
See my comment for reference how to set app delegate (which you will be able then access), however also you can content view directly from window via NSApp, like
NSApp.mainWindow?.contentView
or
NSApp.keyWindow?.contentView
depending on your windows configuration.
I am writing a macOS application with multiple view controllers, using Storyboards.
In my main View Controller I would like to be able to copy and paste data to the NSPasteboard. The data is related to buttons displayed to the user, and the exact data to be copied varies depending on which button has most recently been pressed/selected.
I would like to be able to override the standard behaviour of the Copy and Paste NSMenuItems when my main View Controller is the front most (key) window, but revert to back to standard behaviour when other windows are in the foreground, as they all contain NSTextFields which can be copied/pasted into.
I have done a lot of googling, and overriding this behaviour is not very well documented. I can achieve it globally by adding an IBAction into the App Delegate, which I could use to call a function in whichever View Controller is key, but this doesn't feel like a very elegant solution.
Currently my IBAction in the App Delegate looks like this:
#IBAction func copy(_ sender: Any) {
if let window = NSApplication.shared.keyWindow {
if let splitView = window.contentViewController as? SplitViewController {
if let controlVC = splitView.controlItem.viewController as? ControlViewController {
controlVC.copyAction(self)
}
}
}
}
Am I missing a neater solution?
Thanks,
Dan
In my macOS application, I am following a OAuth-Login procedure.
I am authenticating successfully by receiving a code within a url through my custom url, with which I already can get hold of an access_token.
I start the login procedure with the simple click of a button in a ViewController.
The system I log in to then answers with my registered custom url scheme, providing me with a code I have to then use to get an access_token with POST request. This access_token than can be used to make api calls.
My Problem now is that lacking knowledge of how to implement other techniques, I am currently doing all the latter procedure within the AppDelegate function application(_ application: NSApplication, open urls: [URL]).
From my limited understanding this is the way to handle this, but now
how can I get back from there to get hold of the current view? I am really struggling with the view controller life cycle part of things here I guess...
In AppDelegate, you can get a reference to the current window's ViewController as follows. Replace "MainViewController" with the name of the one you use.
iOS Swift:
if let vc = window?.rootViewController as? MainViewController {
// use `vc` here by calling public functions
// and accessing public properties
}
macOS Swift:
if let vc = NSApplication.shared.mainWindow?.contentViewController as? MainViewController {
// use `vc` here by calling public functions
// and accessing public properties
}
OK, found it: since there is no rootViewController in macOS-land as there is with iOS, it works a little different:
in macOS you can get hold of the window currently "under keyboard" like so:
in application(_:open:), where the redirect_uri gets called:
if let viewController = NSApplication.shared.keyWindow?.contentViewController as? ViewController {
// make changes to the view
}
I'm trying to programmatically show a window in my macOS application. The reason I want to do it programmatically is because the user clicks a Login button and the resulting function depends on the success of the login. If it was successful, the window is shown; otherwise, it is not.
Here is a screenshot of my Xcode window:
Here's what I'm trying in the code (Alert is a class I created to make showing NSAlert dialogs easier):
#IBAction func btnLogin_Click(_ sender: Any) {
let email = txtEmail.stringValue
if(email.isEmpty) {
Alert.show(parent: view.window!, message: "Email is required.")
return
}
let password = txtPassword.stringValue
if(password.isEmpty) {
Alert.show(parent: view.window!, message: "Password is required.")
return
}
// this does not work, even though I gave the window and view controllers
// both identifiers in the storyboard
self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("wcStores"))
}
Apple's documentation for NSStoryboard.SceneIdentifier is pretty much nonexistent, and other methods I've seen seem to pertain to earlier versions of Swift.
What am I doing wrong?
Alright, so this is not what I originally was trying to do, but this way is much better, and what I was really looking for.
let vcStores = self.storyboard?.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("vcStores"))
as! NSViewController
self.view.window?.contentViewController = vcStores
This will just replace the window's contents with the contents in the view vcStores as defined in Interface Builder.
This video also helped, albeit for iOS and Swift 3. I was trying to create a new NSWindow at first because I'm so used to doing desktop development in Java Swing or C# Windows Forms. But I love how easy it is to just switch out the window contents like this.
I'm given an arbitrary NSAttributedString (parsed from markdown, not that it matters here) which may contain URLs that I want to be clickable in a text field within an NSTableView cell. The requirements state that if the user clicks the URL, they be taken to it with the default browser. IF they click anywhere else in the cell, we have default behavior (displaying an additional info popup).
I'm attempting to use a NSTextView to display the content. However, clicking outside the URL but within the view selects the text and eats the mouse click. Making the view not selectable won't allow clicking the URL either. I also don't really want the text to be selectable but that's a minor side problem.
So... I decided to make my view controller an NSTextViewDelegate so I could use some of those callbacks. But my app crashes if I set the NSTextView's delegate property to 'self'. This happens even if I don't implement any of the functions, even though they are all optional.
I'm using Swift 3 and wonder if there's some bug or other issue there? The call stack appears to be sending a textView:willChangeSelectionFromCharacterRanges:toCharacterRanges: message even though it's not implemented. And incidentally, implementing that method isn't helping either.
Any help, or sample code in Swift 3 using the delegate protocol, would be greatly appreciated.
Here's the crash I get by simply setting the delegate property on NSTextView:
By request, here's the code that set's the delegate. Currently I just set it whenever the message changes. This can obviously be optimized but for now I just want to see it work.
var notification: SSNotification! {
didSet {
guard let notificationCellView = self.view as? SSNotificationCellView else { return }
notificationCellView.subjectLabel.stringValue = notification.subject
if let description = notification.message , description != "" {
let attrString = TSMarkdownParser.standard().attributedString(fromMarkdown: description)
notificationCellView.messageLabel.textStorage?.setAttributedString(attrString)
notificationCellView.messageLabel.isHidden = false
notificationCellView.messageLabel.delegate = self
} else {
notificationCellView.messageLabel.isHidden = true
}
}
}
I never did figure out why I was crashing but I was able to come up with a workaround. I was originally trying to make the view controller for the table cell which contained NSTextView be the delegate. I changed it so that the cell's view subclass itself was the delegate and all is well.
I don't get it but it works, so that's what matters.