Open WebView links in Safari View Controller. (Xcode, Swift) - view

I am trying to open various WebView links in a Safari View Controller.
So from within a WebView (Swift) I need to be able to open all external links in Safari View Controller, with the exception of internal links that will open within the WebView (self).

//MARK: Button Click on open with SafariViewController
private var urlString:String = "https://google.com"
#IBAction func openWithSafariVC(sender: AnyObject)
{
let svc = SFSafariViewController(URL: NSURL(string: self.urlString)!)
svc.delegate = self
self.presentViewController(svc, animated: true, completion: nil)
}
//MARK: SafatriViewConroller Dismiss
func safariViewControllerDidFinish(controller: SFSafariViewController)
{
controller.dismissViewControllerAnimated(true, completion: nil)
}

Related

Open New Window in Swift

I am trying to open a new window in my Swift application but I cannot get it to open.
class AppDelegate: NSObject, NSApplicationDelegate
{
func applicationDidFinishLaunching(aNotification: NSNotification)
{
openMyWindow()
}
func openMyWindow()
{
if let storyboard = NSStoryboard(name: "Main",bundle: nil)
{
if let vc = storyboard.instantiateControllerWithIdentifier("MyList") as? MyListViewController
{
var myWindow = NSWindow(contentViewController: vc)
myWindow.makeKeyAndOrderFront(self)
let controller = NSWindowController(window: myWindow)
controller.showWindow(self)
}
}
}
}
I have set the Storyboard ID in IB.
I have traced the code and it does get into the window opening code but it doesn't do anything.
BTW I do have a default storyboard entry point set and that default window opens OK but I need to have a second window open and that is what is not working.
After the openMyWindow() method is executed, the windowController will be released and consequently the window is nil. That's why it is not there.
You have to hold the window in you class to keep it alive, then the window will be visible.
var windowController : NSWindowController?

Button to load different page in same webView

I have a webview loading a local HTML page after pressing a button in a view controller. How would I put a button under the webview to load different content in the same web view?
ViewController has no extra code entered just a button in storyboard with a present modal segue to the webView controller
webView has the following code.
//
// WebViewer.swift
// TestWebView
//
// Created by Colin McGarry on 13/03/15.
// Copyright (c) 2015 Colin McGarry. All rights reserved.
//
import UIKit
class WebViewer: UIViewController {
var page = "2page"
#IBOutlet weak var webView: UIWebView!
#IBAction func close(sender: AnyObject) {
println(sender.tag)
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func reLoad(sender: AnyObject) {
println(sender.tag)
page = "1page"
webView!.reload()
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
if let htmlFile = NSBundle.mainBundle().pathForResource(page, ofType: "html"){
let htmlData = NSData(contentsOfFile: htmlFile)
let baseURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath)
webView.loadData(htmlData, MIMEType: "text/html", textEncodingName: "UTF-8", baseURL: baseURL)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
Under the webView i've placed two buttons, one to close and go back to the viewcontroller, the other I wanted to reload a different webpage in this view.
I tried an if statement with the sender.tag of the reload button but it wasn't recognised. Neither was the segue identifier from the first viewController
I found a solution from an unanswered question.
i changed my reload() function to.
#IBAction func reLoad(sender: AnyObject) {
println(sender.tag)
page = "1page"
if let htmlFile = NSBundle.mainBundle().pathForResource(page, ofType: "html"){
let htmlData = NSData(contentsOfFile: htmlFile)
let baseURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath)
webView.loadData(htmlData, MIMEType: "text/html", textEncodingName: "UTF-8", baseURL: baseURL)
}
}
I'm thinking that it would probably be better to put the repeated code in a function and call it each time.

Connect to ViewController from AppDelegate (Swift)

I have created a new OS X Cocoa Application using the standard Xcode Swift template (using StoryBoards).
I have implemented an IBAction in AppDelegate.swift to handle when the users selects "Open..." from the "File" menu. If the chosen file is a valid image file, I create an NSImage which I then want to display in the view of ViewController.
#IBAction func openFile(sender: NSMenuItem) {
var openPanel = NSOpenPanel()
openPanel.beginWithCompletionHandler { (result :Int) -> Void in
if result == NSFileHandlingPanelOKButton {
if let imageURL = openPanel.URL {
let image = NSImage(contentsOfURL: imageURL)
// PRESENT image IN THE VIEW CONTROLLER
}
}
}
However, I don't see any way to connect to ViewController from AppDelegate. I have only managed to find suggestions that I should look at self.window! in AppDelegate, but there is no such thing as a window in AppDelegate.
Thanks,
Michael Knudsen
It seems that AppDelegate can connect to objects only within Application Scene in a storyboard. If you want to get a ViewController, instantiate it from a storyboard.
sample:
#IBAction func menuAction(sender: AnyObject) {
if let storyboard = NSStoryboard(name: "Main", bundle: nil) {
let controller = storyboard.instantiateControllerWithIdentifier("VC1") as NSViewController
if let window = NSApplication.sharedApplication().mainWindow {
window.contentViewController = controller // just swap
}
}
}
You can access the mainWinow property and the contentViewController property to create a reference to your custom ViewController class. This is similar to the iOS rootViewController property.
let rootViewController = NSApplication.shared().mainWindow?.windowController?.contentViewController as! ViewController
Now you can use this reference to access IBOutlets on your main storyboard from your AppDelegate.
rootViewController.myTextView.textStorage?.mutableString.setString("Cats and dogs.")
This is good for a simple app with one Window with one ViewController.
I was stuck trying to do this same thing recently and managed to get the event I needed to update my view by creating the #IBAction in my ViewController and control dragging to my Application's First Responder (above the menu in my storyboard view).
Here's the question that got me out of the woods:
Application Menu Items Xcode
And thanks to Bluedome for the suggestion to connect it to First Responder's action.
If you control-drag from the menu to the first responder (red cube above menu) and picked an existing action, then you can "responder chain" to your view controller. In my case I attached Open to openFile and then in my view controller I added the following
override var acceptsFirstResponder: Bool {
return true
}
func openFile(sender: NSMenuItem) {
print("In view controller")
}
and it worked without any changes in AppDelegate. Most of the menus are already hooked up to first responder so just add the matching function name in your view controller.
See this comment and this document on Event Handling Basics for more info.
In Swift 5 and accessing new windows array:
#IBAction func menuAction(sender: AnyObject) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateInitialViewController()
// The windows in the array are ordered from back to front by window level;
// thus, the last window in the array is on top of all other app windows.
// On app launch, UIApplication.shared.windows.count == 1 anyway.
if let window = UIApplication.shared.windows.last {
window.rootViewController = controller
}
}

Adding function to sidebar menu on Swift

So I just did a tutorial on adding a blurry sidebar menu. I replicated the code but I cant seem to find out how to call my other ViewControllers I made in storyboard mode.
I have created files and linked them to UIViewControllers. But when I try to call that ViewController with my sidebar menu I'm getting a black screen.
Here is the link of the files I used to follow along http://goo.gl/ULWxJh
And here is the link of the youtube video I followed along with http://www.youtube.com/watch?v=qaLiZgUK2T0
Not sure why! Any help would be greatly appreciated
class ViewController: UIViewController, SideBarDelegate {
var sideBar:SideBar = SideBar() // Side Bar
override func viewDidLoad() {
super.viewDidLoad()
// Side bar action and text
sideBar = SideBar(sourceView: self.view, menuItems: ["Home", "Business Directory", "Classifieds", "Featured News", "Jobs", "Restaurants", "Sports"])
sideBar.delegate = self
}
// Side Bar funcion
func sideBarDidSelectButtonAtIndex(index: Int) {
if index == 0{
let vc = ViewController()
self.presentViewController(vc, animated: true, completion: nil)
}else if index == 1{
let vc = businessDirectoryVC()
self.presentViewController(vc, animated: true, completion: nil)
}
}
}
Add a Storyboard ID (in this case "view") to the View Controller in your Main Storyboard and then add the following to the file from where you want to call the sidebar from:
func sideBarDidSelectButtonAtIndex(index: Int) {
if index == 0 {
let storyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let showView = storyBoard.instantiateViewControllerWithIdentifier("view") as! ViewController
self.presentViewController(showUebersicht, animated:true, completion:nil)
}
}
Value "0" stands for the first item in the sidebar. Change the value for another value of the array where the items of the sidebar are stored.

How to present a modal atop the current view in Swift

(Xcode6, iOS8, Swift, iPad)
I am trying to create a classic Web-like modal view, where the outside of the dialog box is "grayed-out." To accomplish this, I've set the alpha value of the backgroundColor of the view for the modal to 0.5, like so:
self.view.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.5)
The only problem is that when the modal becomes full-screen, the presenting view is removed. (Ref Transparent Modal View on Navigation Controller).
(A bit irritated at the concept here. Why remove the underlying view? A modal is, by definition, to appear atop other content. Once the underlying view is removed, it's not really a modal anymore. it's somewhere between a modal and a push transition. Wa wa wa... Anyway..)
To prevent this from happening, I've set the modalPresentationStyle to CurrentContext in the viewDidLoad method of the parent controller, and in Storyboard... but no luck.
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
How do I prevent the presenting view from being removed when the modal becomes full screen?
tyvm.. more info below.
Also in Storyboard, like so (Presentation: Current Context)
Thx for your help... documentation below:
First, remove all explicit setting of modal presentation style in code and do the following:
In the storyboard set the ModalViewController's modalPresentation style to Over Current context
Check the checkboxes in the Root/Presenting ViewController - Provide Context and Define Context.
They seem to be working even unchecked.
You can try this code for Swift:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
let navigationController = UINavigationController(rootViewController: popup)
navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.presentViewController(navigationController, animated: true, completion: nil)
For swift 4 latest syntax using extension:
extension UIViewController {
func presentOnRoot(`with` viewController : UIViewController){
let navigationController = UINavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.present(navigationController, animated: false, completion: nil)
}
}
How to use:
let popup : PopupVC = self.storyboard?.instantiateViewControllerWithIdentifier("PopupVC") as! PopupVC
self.presentOnRoot(with: popup)
The only problem I can see in your code is that you are using CurrentContext instead of OverCurrentContext.
So, replace this:
self.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
for this:
self.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
self.navigationController.modalPresentationStyle = UIModalPresentationStyle.OverCurrentContext
This worked for me in Swift 5.0. Set the Storyboard Id in the identity inspector as "destinationVC".
#IBAction func buttonTapped(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let destVC = storyboard.instantiateViewController(withIdentifier: "destinationVC") as! MyViewController
destVC.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
destVC.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(destVC, animated: true, completion: nil)
}
The problem with setting the modalPresentationStyle from code was that you should have set it in the init() method of the presented view controller, not the parent view controller.
From UIKit docs: "Defines the transition style that will be used for this view controller when it is presented modally. Set
this property on the view controller to be presented, not the presenter. Defaults to
UIModalTransitionStyleCoverVertical."
The viewDidLoad method will only be called after you already presented the view controller.
The second problem was that you should use UIModalPresentationStyle.overCurrentContext.
The only way I able to get this to work was by doing this on the presenting view controller:
func didTapButton() {
self.definesPresentationContext = true
self.modalTransitionStyle = .crossDissolve
let yourVC = self.storyboard?.instantiateViewController(withIdentifier: "YourViewController") as! YourViewController
let navController = UINavigationController(rootViewController: yourVC)
navController.modalPresentationStyle = .overCurrentContext
navController.modalTransitionStyle = .crossDissolve
self.present(navController, animated: true, completion: nil)
}
I am updating a simple solution. First add an id to your segue which presents modal. Than in properties change it's presentation style to "Over Current Context". Than add this code in presenting view controller (The controller which is presenting modal).
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let Device = UIDevice.currentDevice()
let iosVersion = NSString(string: Device.systemVersion).doubleValue
let iOS8 = iosVersion >= 8
let iOS7 = iosVersion >= 7 && iosVersion < 8
if((segue.identifier == "chatTable")){
if (iOS8){
}
else {
self.navigationController?.modalPresentationStyle = UIModalPresentationStyle.CurrentContext
}
}
}
Make sure you change segue.identifier to your own id ;)

Resources