How to Detect Back Swipe in WkWebView - ios

Is it possible to detect a back swipe in a web view when there has not been any forward navigation? The following code works fine if the user has moved off the first page but I want to know if they back swiped while on that page.
Update - This is the code I'm using after modifying it per comments. I added the navigation back function and the swipe gesture.
class WebViewClient: UIViewController, WKUIDelegate, WKNavigationDelegate, UIGestureRecognizerDelegate
{
var webView: WKWebView!
public func load(pageLink page: String)
{
print("Opening: " + page)
if webView != nil
{
if let myURL = URL(string:page)
{
webUrlRequest = page
let myRequest = URLRequest(url: myURL)
webView.load(myRequest)
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!)
{
print("Opened: " + webUrlRequest)
}
override func loadView()
{
let pref = WKPreferences()
pref.javaScriptEnabled = true
let config = WKWebViewConfiguration()
config.preferences = pref
webView = WKWebView(frame: .zero, configuration: config)
webView.uiDelegate = self
webView.navigationDelegate = self
webView.allowsBackForwardNavigationGestures = true
view = webView
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: #escaping (WKNavigationActionPolicy) -> Void)
{
if navigationAction.navigationType == .backForward && webView.backForwardList.backList.count == 0
{
print("Can't go back any more")
}
decisionHandler(.allow)
}
#objc func backNavigationFunction(_ sender: UIScreenEdgePanGestureRecognizer)
{
let dX = sender.translation(in: view).x
if sender.state == .ended
{
let fraction = abs(dX / view.bounds.width)
if fraction >= 0.35
{
print("Back swipe")
//back navigation code here
}
}
}
override func viewDidLoad()
{
super.viewDidLoad()
let swipeGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(backNavigationFunction(_:)))
swipeGesture.edges = .left
swipeGesture.delegate = self
webView.addGestureRecognizer(swipeGesture)
}
}

I would implement a UIScreenEdgePanGestureRecognizer to handle this. Add the following to your viewDidLoad
let swipeGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(backNavigationFunction(_:)))
swipeGesture.edges = .left
swipeGesture.delegate = self
view.addGestureRecognizer(swipeGesture)
Then, implement a function to handle the backNavigationFunction like below:
#objc func backNavigationFunction(_ sender: UIScreenEdgePanGestureRecognizer) {
let dX = sender.translation(in: view).x
if sender.state == .ended {
let fraction = abs(dX / view.bounds.width)
if fraction >= 0.35 {
//back navigation code here
}
}
}
Don't forget to make the ViewController inherit from the UIGestureRecognizerDelegate class (i.e. class WebViewController: UIViewController, WKUIDelegate, WKNavigationDelegate, UIGestureRecognizerDelegate). The delegate in question here is UIGestureRecognizerDelegate but I anticipate you'll need the others as well.

Related

WKWebView.scrollView.bounces = false is Not working

I click the button to go to another Webview. However, I removed the bounce from the moved Webview, but it does not work.
First WKWebView
var openSecondScreen : SecondWebViewController!
var preloadCheck = false
...
func openSecondScreen(){
let storyboard = UIStoryboard(name: "Main", bundle: nil)
openSecondScreen = storyboard.instantiateViewController(withIdentifier: "SecondWebViewController") as! SecondWebViewController
openSecondScreen.delegate = self
openSecondScreen.loadViewIfNeeded()
openSecondScreen.secondWKWebView.navigationDelegate = self
preloadCheck = true
}
....
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
if preloadCheck {
self.navigationController?.pushViewController(openSecondScreen, animated: true)
preloadCheck = false
}
}
Second WKWebView
#IBOutlet var secondWKWebView: WKWebView!
...
override func loadView() {
super.loadView()
secondWKWebView.uiDelegate = self
secondWKWebView.navigationDelegate = self
secondWKWebView.scrollView.delegate = self
...
}
extension SecondWebViewController: UIScrollViewDelegate{
func scrollViewDidScroll(_ scrollView: UIScrollView) {
print("scrollViewDidScroll")
scrollView.bounces = false
}
}
Scroll does not display the log. Therefore, the function does not work either.
Editing: I don't think I wrote this down in advance. I'm even setting it up in advance.But it didn't work
override func viewDidLoad() {
super.viewDidLoad()
secondWKWebView.scrollView.bounces = false
}
Thanks in advance

ViewController is loading always the same link

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

Swift 3: Preload SecondViewController's WKWebView ahead of click

I need some help.
I want to preload my webView in Second View Controller after the webView in the First View Controller is done.
I believe I need to use a notification center post/observe to call my loadWebView-function in my Second View Controller but don't know how. Any suggestions is appreciated.
FirstViewController.swift
import UIKit;
import WebKit;
class FirstViewController: UIViewController, WKNavigationDelegate {
let webView:WKWebView = WKWebView(frame: CGRectMake(0, 0, UIScreen.main.bounds.width, UIScreen.main.bounds.height))
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!) {
print("loaded!")
webView.isHidden = false
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.google.com")
webView.navigationDelegate = self
webView.load(URLRequest(url: url!))
webView.isHidden = true
self.view.addSubview(webView)
}
}
SecondViewController.swift
import UIKit
import WebKit
class SecondViewController: UIViewController, WKNavigationDelegate {
let webView:WKWebView = WKWebView(frame: CGRectMake(0, 0, UIScreen.main.bounds.width, UIScreen.main.bounds.height))
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!) {
print("loaded!")
webView.isHidden = false
}
override func viewDidLoad() {
super.viewDidLoad()
}
func loadWebView() {
let url = URL(string: "https://www.amazon.com")
webView.navigationDelegate = self
webView.load(URLRequest(url: url!))
webView.isHidden = true
self.view.addSubview(webView)
}
}
In First VC :
func webView(_ webView: WKWebView,
didFinish navigation: WKNavigation!) {
//Post notification
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "WebViewFinishedLoading"), object: nil)
}
In Second VC:
override func viewDidLoad() {
super.viewDidLoad()
// Add observer for your notification
NotificationCenter.default.addObserver(self, selector: #selector(loadWebView), name: NSNotification.Name(rawValue: "WebViewFinishedLoading"), object: nil)
}
//Remove observer in deinit
deinit {
NotificationCenter.default.removeObserver(self)
}

Swift javascript/ios bridge breaks swipe gesture recognizer

I have a swipe gesture recognizer to bring a toolbar off and on the screen. It was working beautifully until I added a JavaScript to iOS bridge using WKUserContentController(). The bridge works, successfully printing the JavaScript message, but swiping no longer works. But if I comment out Webview = WKWebView(frame: self.view.frame, configuration: configuration) and view.addSubview(Webview) the bridge is obviously broken, but the gesture recognizer works. I just can't get them both working at the same time. Where have I gone wrong?
Edit: Maybe this is relevant: with the code as below, the activity indicator does not appear when the WebView is loading. Also, if I comment out the lines that start the toolbar hidden (starting point swiped off the page), the toolbar should appear, but it doesn't:
import UIKit
import WebKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate,
WKNavigationDelegate, WKScriptMessageHandler {
let locationManager = CLLocationManager()
#IBOutlet var Webview: WKWebView!
#IBOutlet var ActInd: UIActivityIndicatorView!
#IBOutlet var Toolbar: UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
let controller = WKUserContentController()
controller.add(self, name: "SwiftNative")
let configuration = WKWebViewConfiguration()
configuration.userContentController = controller
// commenting out these two lines disables the bridge but activates swiping again
Webview = WKWebView(frame: self.view.frame, configuration: configuration)
view.addSubview(Webview)
let url = URL(string: "https://www.bazleysawesomesite.com")
let request = URLRequest(url: url!)
Webview.load(request)
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
let rightSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(_:)))
let leftSwipe = UISwipeGestureRecognizer(target: self, action: #selector(ViewController.handleSwipes(_:)))
rightSwipe.direction = .right
leftSwipe.direction = .left
view.addGestureRecognizer(rightSwipe)
view.addGestureRecognizer(leftSwipe)
self.view.backgroundColor = UIColor.black
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
print("Message from beyond: \(message.body)")
}
// Make the status bar text light
override var preferredStatusBarStyle : UIStatusBarStyle {
return UIStatusBarStyle.lightContent
}
// Start the toolbar "hidden"
// commenting out these lines should make the toolbar appear, but it doesn't
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
Toolbar.center.x = Toolbar.center.x - self.view.frame.width
}
// Activity Indicator stuff
func webViewDidStartLoad(_ : WKWebView) {
ActInd.startAnimating()
}
func webViewDidFinishLoad(_ : WKWebView) {
ActInd.stopAnimating()
if self.Toolbar.center.x > 0 {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.Toolbar.center.x = self.Toolbar.center.x - self.view.frame.width
})
}
}
// handle swipes
func handleSwipes(_ sender:UISwipeGestureRecognizer) {
if (sender.direction == .right) {
if self.Toolbar.center.x < 0 {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.Toolbar.center.x = self.Toolbar.center.x + self.view.frame.width
})
}
}
if (sender.direction == .left) {
if self.Toolbar.center.x > 0 {
UIView.animate(withDuration: 0.3, animations: { () -> Void in
self.Toolbar.center.x = self.Toolbar.center.x - self.view.frame.width
})
}
}
}
}

Swift WKWebView and Javascript Interaction

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 = '...'

Resources