How do I remove the "Wrapper" element and buttons "back" and "menu" from main.storyboard? but to keep loading bar I tried to delete part of the code but it gives errors.
I will be very happy if someone helps me. Thank you very much in advance for your help.
Below you will find the code I use
ViewController.swift:
import WebKit
class ViewController: UIViewController {
// MARK: Outlets
@IBOutlet weak var leftButton: UIBarButtonItem!
@IBOutlet weak var rightButton: UIBarButtonItem!
@IBOutlet weak var webViewContainer: UIView!
@IBOutlet weak var offlineView: UIView!
@IBOutlet weak var offlineIcon: UIImageView!
@IBOutlet weak var offlineButton: UIButton!
@IBOutlet weak var activityIndicatorView: UIView!
@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
// MARK: Globals
var webView: WKWebView!
var tempView: WKWebView!
var progressBar : UIProgressView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.title = appTitle
setupApp()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// UI Actions
// handle back press
@IBAction func onLeftButtonClick(_ sender: Any) {
if (webView.canGoBack) {
webView.goBack()
// fix a glitch, as the above seems to trigger observeValue -> WKWebView.isLoading
activityIndicatorView.isHidden = true
activityIndicator.stopAnimating()
} else {
// exit app
UIControl().sendAction(#selector(URLSessionTask.suspend), to: UIApplication.shared, for: nil)
}
}
// open menu in page, or fire alternate function on large screens
@IBAction func onRightButtonClick(_ sender: Any) {
if (changeMenuButtonOnWideScreens && isWideScreen()) {
webView.evaluateJavaScript(alternateRightButtonJavascript, completionHandler: nil)
} else {
webView.evaluateJavaScript(menuButtonJavascript, completionHandler: nil)
}
}
// reload page from offline screen
@IBAction func onOfflineButtonClick(_ sender: Any) {
offlineView.isHidden = true
webViewContainer.isHidden = false
loadAppUrl()
}
// Observers for updating UI
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if (keyPath == #keyPath(WKWebView.isLoading)) {
// show activity indicator
/*
// this causes troubles when swiping back and forward.
// having this disabled means that the activity view is only shown on the startup of the app.
// ...which is fair enough.
if (webView.isLoading) {
activityIndicatorView.isHidden = false
activityIndicator.startAnimating()
}
*/
}
if (keyPath == #keyPath(WKWebView.estimatedProgress)) {
progressBar.progress = Float(webView.estimatedProgress)
rightButton.isEnabled = (webView.estimatedProgress == 1)
}
}
// Initialize WKWebView
func setupWebView() {
// set up webview
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: webViewContainer.frame.width, height: webViewContainer.frame.height))
webView.navigationDelegate = self
webView.uiDelegate = self
webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
webViewContainer.addSubview(webView)
// settings
webView.allowsBackForwardNavigationGestures = true
webView.configuration.preferences.javaScriptEnabled = true
if #available(iOS 10.0, *) {
webView.configuration.ignoresViewportScaleLimits = false
}
// user agent
if #available(iOS 9.0, *) {
if (useCustomUserAgent) {
webView.customUserAgent = customUserAgent
}
if (useUserAgentPostfix) {
if (useCustomUserAgent) {
webView.customUserAgent = customUserAgent + " " + userAgentPostfix
} else {
tempView = WKWebView(frame: .zero)
tempView.evaluateJavaScript("navigator.userAgent", completionHandler: { (result, error) in
if let resultObject = result {
self.webView.customUserAgent = (String(describing: resultObject) + " " + userAgentPostfix)
self.tempView = nil
}
})
}
}
webView.configuration.applicationNameForUserAgent = ""
}
// bounces
webView.scrollView.bounces = enableBounceWhenScrolling
// init observers
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.isLoading), options: NSKeyValueObservingOptions.new, context: nil)
webView.addObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress), options: NSKeyValueObservingOptions.new, context: nil)
}
// Initialize UI elements
// call after WebView has been initialized
func setupUI() {
// leftButton.isEnabled = false
// progress bar
progressBar = UIProgressView(frame: CGRect(x: 0, y: 0, width: webViewContainer.frame.width, height: 40))
progressBar.autoresizingMask = [.flexibleWidth]
progressBar.progress = 0.0
progressBar.tintColor = progressBarColor
webView.addSubview(progressBar)
// activity indicator
activityIndicator.color = activityIndicatorColor
activityIndicator.startAnimating()
// offline container
offlineIcon.tintColor = offlineIconColor
offlineButton.tintColor = buttonColor
offlineView.isHidden = true
// setup navigation bar
if (forceLargeTitle) {
if #available(iOS 11.0, *) {
navigationItem.largeTitleDisplayMode = UINavigationItem.LargeTitleDisplayMode.always
}
}
if (useLightStatusBarStyle) {
self.navigationController?.navigationBar.barStyle = UIBarStyle.black
}
// handle menu button changes
/// set default
rightButton.title = menuButtonTitle
/// update if necessary
updateRightButtonTitle(invert: false)
/// create callback for device rotation
let deviceRotationCallback : (Notification) -> Void = { _ in
// this fires BEFORE the UI is updated, so we check for the opposite orientation,
// if it's not the initial setup
self.updateRightButtonTitle(invert: true)
}
/// listen for device rotation
NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main, using: deviceRotationCallback)
/*
// @DEBUG: test offline view
offlineView.isHidden = false
webViewContainer.isHidden = true
*/
}
// load startpage
func loadAppUrl() {
let urlRequest = URLRequest(url: webAppUrl!)
webView.load(urlRequest)
}
// Initialize App and start loading
func setupApp() {
setupWebView()
setupUI()
loadAppUrl()
}
// Cleanup
deinit {
webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.isLoading))
webView.removeObserver(self, forKeyPath: #keyPath(WKWebView.estimatedProgress))
NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
}
// Helper method to determine wide screen width
func isWideScreen() -> Bool {
// this considers device orientation too.
if (UIScreen.main.bounds.width >= wideScreenMinWidth) {
return true
} else {
return false
}
}
// UI Helper method to update right button text according to available screen width
func updateRightButtonTitle(invert: Bool) {
if (changeMenuButtonOnWideScreens) {
// first, check if device is wide enough to
if (UIScreen.main.fixedCoordinateSpace.bounds.height < wideScreenMinWidth) {
// long side of the screen is not long enough, don't need to update
return
}
// second, check if both portrait and landscape would fit
if (UIScreen.main.fixedCoordinateSpace.bounds.height >= wideScreenMinWidth
&& UIScreen.main.fixedCoordinateSpace.bounds.width >= wideScreenMinWidth) {
// both orientations are considered "wide"
rightButton.title = alternateRightButtonTitle
return
}
// if we land here, check the current screen width.
// we need to flip it around in some cases though, as our callback is triggered before the UI is updated
let changeToAlternateTitle = invert
? !isWideScreen()
: isWideScreen()
if (changeToAlternateTitle) {
rightButton.title = alternateRightButtonTitle
} else {
rightButton.title = menuButtonTitle
}
}
}
}
// WebView Event Listeners
extension ViewController: WKNavigationDelegate {
// didFinish
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// set title
if (changeAppTitleToPageTitle) {
navigationItem.title = webView.title
}
// hide progress bar after initial load
progressBar.isHidden = true
// hide activity indicator
activityIndicatorView.isHidden = true
activityIndicator.stopAnimating()
}
// didFailProvisionalNavigation
// == we are offline / page not available
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
// show offline screen
offlineView.isHidden = false
webViewContainer.isHidden = true
}
}
// WebView additional handlers
extension ViewController: WKUIDelegate {
// handle links opening in new tabs
func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if (navigationAction.targetFrame == nil) {
webView.load(navigationAction.request)
}
return nil
}
// restrict navigation to target host, open external links in 3rd party apps
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if let requestUrl = navigationAction.request.url {
if let requestHost = requestUrl.host {
if (requestHost.range(of: allowedOrigin) != nil ) {
decisionHandler(.allow)
} else {
decisionHandler(.cancel)
if (UIApplication.shared.canOpenURL(requestUrl)) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(requestUrl)
} else {
// Fallback on earlier versions
UIApplication.shared.openURL(requestUrl)
}
}
}
} else {
decisionHandler(.cancel)
}
}
}
}
AppDelegate.swift:
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Change Navigation style
UINavigationBar.appearance().barTintColor = navigationBarColor
UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: navigationTitleColor]
UIBarButtonItem.appearance().tintColor = navigationButtonColor
if #available(iOS 11.0, *) {
UINavigationBar.appearance().largeTitleTextAttributes = [NSAttributedString.Key.foregroundColor: navigationTitleColor]
}
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}