language: swift 3.0
os: macOS 10.12.3
xcode: 8.2.1
Here is a blank Storyboard with a ViewController.
And below is the code:
import UIKit
import WebKit
class CommonWebViewViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
let backButton = UIBarButtonItem(title: "BACK", style: .plain, target: self, action: #selector(goBack))
let closeButton = UIBarButtonItem(title: "CLOSE", style: .plain, target: nil, action: #selector(close))
let webview = WKWebView()
var url = ""
override func viewDidLoad() {
super.viewDidLoad()
view = webview
navigationItem.setLeftBarButtonItems([backButton], animated: true)
webview.uiDelegate = self
webview.navigationDelegate = self
webview.allowsBackForwardNavigationGestures = true
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
title = webView.title
}
func load(withUrl url: String) {
self.url = url
webview.load(URLRequest(url: URL(string: self.url)!))
}
func goBack() {
if webview.canGoBack {
webview.goBack()
navigationItem.leftBarButtonItems?.append(closeButton)
}
else {
close()
}
}
func close() {
_ = self.navigationController?.popViewController(animated: true)
}
}
I want to make a browser, and when I tap the BACK button, there's no response unless I click a link in webview.
P.S if I create the UIBarButtonItem object in viewDidload method, the problem will be solved.
Related
I have created a WKWebView programmatically with some UIBarButtonItems. A "Open" button on the top right, and 3 UIToolbarItems on the bottom for ProgressView, flexibleSpace, and reload button. My simulator is not able to load these onto the screen and looks like it is loaded improperly on the simulator.
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
var progressView: UIProgressView!
var websites = ["apple.com", "google.com"]
//loadView() func
override func loadView() {
//create an instance of WKWebView()
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
//get URL and make a load URLRequest
guard let url = URL(string: "https://www." + websites[0]) else { return }
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true
//set BarButtonItem on the top right of page
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Open", style: .plain, target: self, action: #selector(openTapped))
//add UIToolbar items with UIBarButtonItems
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let reload = UIBarButtonItem(barButtonSystemItem: .refresh, target: webView, action: #selector(webView.reload))
//add progressView
progressView = UIProgressView(progressViewStyle: .default)
progressView.sizeToFit()
let progressButton = UIBarButtonItem(customView: progressView)
//add items to toolbarItems array
toolbarItems = [progressButton, spacer, reload]
navigationController?.isToolbarHidden = false
//create actionSheet UIAlertActionController for bar button drop down
#objc func openTapped() {
let alert = UIAlertController(title: "Open new page!", message: nil, preferredStyle: .actionSheet)
for website in websites {
alert.addAction(UIAlertAction(title: website, style: .default, handler: openPage))
}
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
alert.popoverPresentationController?.barButtonItem = self.navigationItem.rightBarButtonItem
present(alert, animated: true)
}
//handlers for each UIAlertAction
func openPage(action: UIAlertAction) {
guard let actionTitle = action.title else { return }
guard let url = URL(string: "https://" + actionTitle) else { return }
webView.load(URLRequest(url: url))
}
//set webView title to web page title
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
title = webView.title
}
I have tried different screen sizes, but none seem to make UIBarButtonItems and UIToolbarItems appear on simulator.
what my iphoneXR simulator looks like at the moment
You need to embedded your ViewController in a Navigation Controller.
Open your storyboard -> Editor -> Embed in -> Navigation Controller.
Also, your code is missing a curly brace after navigationController?.isToolbarHidden = false to close the viewDidLoad method.
I have the following code for the DatePickerController:
import UIKit
#objc protocol DatePickerControllerDelegate: AnyObject {
func datePicker(controller: DatePickerController, didSelect date: Date)
func datepickerDidDismiss(controller: DatePickerController)
}
final class DatePickerController: UIViewController {
#objc weak var delegate: DatePickerControllerDelegate?
#objc public var date: Date {
get {
return datePicker.date
}
set(value) {
datePicker.setDate(value, animated: false)
}
}
#objc public lazy var datePicker: UIDatePicker = {
let v = UIDatePicker()
v.datePickerMode = .date
return v
}()
override var preferredContentSize: CGSize {
get {
return datePicker.frame.size
}
set(newValue) {
super.preferredContentSize = newValue
}
}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(datePicker)
datePicker.autoresizingMask = [.flexibleTopMargin, .flexibleRightMargin, .flexibleLeftMargin, .flexibleBottomMargin]
view.backgroundColor = .white
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done,
target: self,
action: #selector(DatePickerController.doneButtonDidTap))
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(DatePickerController.cancelButtonDidTap))
}
#objc private func doneButtonDidTap() {
delegate?.datePicker(controller: self, didSelect: date)
}
#objc private func cancelButtonDidTap() {
dismiss(animated: true, completion: nil)
delegate?.datepickerDidDismiss(controller: self)
}
}
It works well on iPad:
However, on iPhone the picker slides up under the UINavigationBar:
The code used to show the DatePickerController is absolutely the same, the style is UIModalPresentationStylePopover in both cases.
Update: code to present DatePickerController:
#objc func presentDatePicker() {
let picker = DatePickerController()
let navC = UINavigationController(rootViewController: picker)
present(navC, animated: true, completion: nil)
}
Fixed using AutoLayout:
private func configureLayout() {
datePicker.translatesAutoresizingMaskIntoConstraints = false
[datePicker.topAnchor.constraint(equalTo: view.layoutMarginsGuide.topAnchor),
datePicker.leadingAnchor.constraint(equalTo: view.leadingAnchor),
datePicker.trailingAnchor.constraint(equalTo: view.trailingAnchor),]
.forEach{$0.isActive = true}
}
I am new to swift and ios.The View Controller launch always the same link and do do not show the grid menu with buttons that is in second scene.What i am doing wrong here?
I have in main.storyboard three scene.
In the first scene is navigation.The second scene is a grid menu with buttons that depending on the button click will open a link in webview located in the 3rd scene.The third scene includes a view that should open a specific link depending on the click button in step 2
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView : WKWebView!
var webi:String = "https://www.google.al"
override func viewDidLoad() {
print("‼️OMG:viewDidLoad", webi)
super.viewDidLoad()
let url = URL(string: webi)!
webView.load(URLRequest(url: url))
let refresh = UIBarButtonItem(barButtonSystemItem: .refresh, target: webView, action: #selector(webView.reload))
toolbarItems = [refresh]
navigationController?.isToolbarHidden = false
}
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
}
#IBAction func Menu1(_ sender: Any) {
print("‼️OMG:viewDidLoad with menu1")
webi = "https://www.menu1.com"
}
#IBAction func Menu2(_ sender: Any) {
print("‼️OMG:viewDidLoad with menu1")
webi = "https://www.menu2.com"
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
title = webView.title
}
}
Your problem is that you change the urlStr webi without reloading the webview again
func refresh() {
let url = URL(string: webi)!
webView.load(URLRequest(url: url))
}
#IBAction func Menu1(_ sender: Any) {
print("‼️OMG:viewDidLoad with menu1")
webi = "https://www.menu1.com"
self.refresh()
}
#IBAction func menu2(_ sender: Any) {
print("‼️OMG:viewDidLoad with menu1") // other link
webi = "https://www.menu1.com"
self.refresh()
}
///
Navigation->buttons Menu VC -> webViewVC
while your are in buttons menu
let vc = ViewController()
vc.webi = "" // set link according to the clicked button
self.navigationController?.pushViewController(vc,animated:true)
Look to this Demo
How can I set a rule such that when my user clicks any web link within my app, it opens in the in-app browser instead of Safari?
Context: I'm building an app that has several places where links are either embedded by me or are loaded through various user interactions, e.g. a link leading to a page that houses another link. I want to ensure that the user seldom leaves my app and hence want to open all external web links in an in-app browser that has already been developed
Target Build: iOS 11.
Environment/ Language: Swift 4
Simple solution using SFSafariViewController which available in a separate package
import SafariServices
Swift 4, iOS 9.0+
let url = URL(string: "your URL here")
let vc = SFSafariViewController(url: url)
present(vc, animated: true)
If you need more control - use Configuration parameter (Swift 4, iOS 11.0+):
Example:
let config = SFSafariViewController.Configuration()
config.entersReaderIfAvailable = true
let url = URL(string: "your URL here")
let vc = SFSafariViewController(url: url, configuration: config)
present(vc, animated: true)
...it opens in the in-app browser instead of Safari?
In that case, you would need your own WebView. Here's a quick snippet of a simple webView inside a controller:
import UIKit
import WebKit
/// The controller for handling webviews.
class WebViewController: UIViewController {
// MARK: - Properties
internal lazy var button_Close: UIButton = {
let button = UIButton(type: .custom)
button.setImage(.close, for: .normal)
button.imageEdgeInsets = UIEdgeInsets.init(top: 0, left: -30, bottom: 0, right: 0)
button.addTarget(self, action: #selector(back(_:)), for: .touchUpInside)
return button
}()
public var urlString: String! {
didSet {
if let url = URL(string: urlString) {
let urlRequest = URLRequest(url:url)
self.webView.load(urlRequest)
}
}
}
private lazy var webView: WKWebView = {
let webView = WKWebView()
webView.navigationDelegate = self
return webView
}()
// MARK: - Functions
// MARK: Overrides
override func viewDidLoad() {
super.viewDidLoad()
let barButton = UIBarButtonItem(customView: self.button_Close)
self.button_Close.frame = CGRect(x: 0, y: 0, width: 55.0, height: 44.0)
let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: nil, action: nil)
if #available(iOS 11.0, *) {
negativeSpacer.width = -30
}
self.navigationItem.leftBarButtonItems = [negativeSpacer, barButton]
self.view.addSubview(self.webView)
self.webView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
#objc func back(_ sender: Any) {
self.dismiss()
}
}
extension WebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
// Show here a HUD or any loader
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// Dismiss your HUD
}
}
and presenting such webViewController, like so (passing a URLString):
let webViewVC = WebViewController()
webViewVC.urlString = "https://www.glennvon.com/"
let navCon = UINavigationController(rootViewController: webViewVC)
self.navigationController?.present(navCon, animated: true, completion: nil)
If you're using storyboard, then simply drag a webview in your controller and setup the delegate. This should help you out :)
I've been having trouble getting a WKWebView in Swift to trigger some javascript in the loaded web page. Im just trying to use javascript to change a background color on the website if the user swipes left, swipes right, or clicks a button. Any help is greatly appreciated.
import UIKit
import WebKit
class myViewController: UIViewController, WKNavigationDelegate {
#IBOutlet var container: UIView!
var webView: WKWebView?
override func viewDidLoad() {
super.viewDidLoad()
self.webView = WKWebView()
container.addSubview(webView!)
webView?.allowsBackForwardNavigationGestures = true
webView?.navigationDelegate = self
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(myViewController.handleSwipes(_:)))
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(myViewController.handleSwipes(_:)))
leftSwipe.direction = .Left
rightSwipe.direction = .Right
view.addGestureRecognizer(leftSwipe)
view.addGestureRecognizer(rightSwipe)
}
override func viewDidAppear(animated: Bool) {
let frame = CGRectMake(0, 0, container.bounds.width, container.bounds.height)
webView!.frame = frame
let url = NSURL(string: "https://www.google.com")
let request = NSURLRequest(URL: url!)
self.webView!.loadRequest(request)
}
#IBAction func buttonClick(sender: AnyObject) {
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='red';", completionHandler: nil)
}
func handleSwipes(sender:UISwipeGestureRecognizer){
if (sender.direction == .Left){
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='black';", completionHandler: nil)
}
if (sender.direction == .Right){
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='green';", completionHandler: nil)
}
}
func webView(webView: WKWebView, didFinishNavigation navigation: WKNavigation!) {
webView?.evaluateJavaScript("document.getElementByID('hplogo').style.backgroundColor='red';", completionHandler: nil)
}
}
You misspelled the Javascript's function name. It should be getElementById instead of getElementByID:
document.getElementById('hplogo').style.backgroundColor = '...'