I have a very simple web view project which just loads a website. There is a bug though, the website content is showing in the status bar if I scroll down.
I read that this is because the background color of the ViewController is set to be transparent, how can I change it to another color?
I tried it like this:
let color = UIColor.black;
self.view.backgroundColor = color
But nothing changes
Whole Code:
ViewController.swift
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
#IBOutlet var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
// 1 The webView loads the url using an URLRequest object.
let url = URL(string: "https://www.blizz-z.de/")!
webView.load(URLRequest(url: url))
// 2 A refresh item is added to the toolbar which will refresh the current webpage.
let refresh = UIBarButtonItem(
barButtonSystemItem: .refresh,
target: webView,
action: #selector(webView.reload)
)
toolbarItems = [refresh]
navigationController?.isToolbarHidden = true
navigationController?.isNavigationBarHidden = true
}
override func loadView() {
webView = WKWebView()
webView.navigationDelegate = self
view = webView
let color = UIColor.black;
self.view.backgroundColor = color
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
title = webView.title
}
}
I could just disable the status bar with the following code to fix the bug, but I try to keep it:
override var prefersStatusBarHidden: Bool {
return true
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let height = UIScreen.main.bounds.height
let width = UIScreen.main.bounds.width
let webView = WKWebView(frame: CGRect(x: 0, y: 0, width: width, height: height))
webView.load(URLRequest(url: (URL(string: "https://www.blizz-z.de/")!)))
view.addSubview(webView)
UIApplication.shared.statusBarView?.backgroundColor = #colorLiteral(red: 0.9529411765, green: 0.9529411765, blue: 0.9529411765, alpha: 1)
}
}
extension UIApplication {
var statusBarView: UIView? {
if responds(to: Selector("statusBar")) {
return value(forKey: "statusBar") as? UIView
}
return nil
}
}
Make the webView.top constraint relative to safeArea.top constraint, and not the superview.top constraint. This allows you to make your webView under the status bar.
Related
I create a NavigationController with a large title NavigationBar with this code.
class NavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
let appearance = UIBarButtonItem.appearance()
appearance.setBackButtonTitlePositionAdjustment(UIOffset.init(horizontal: 0.0, vertical: -60), for: .default)
self.navigationBar.barTintColor = UIColor.white
self.navigationBar.prefersLargeTitles = true
self.navigationBar.isTranslucent = true
self.navigationBar.tintColor = UIColor.black
}
}
Everything works fine, but when my WKWebView is loaded, somehow the large title bar collapsed automatically without any ScrollViewDelegate code. Please take a look at my gif here to clarify
Here is my WKWebView code.
class resultViewController: UIViewController
{
private var webView: WKWebView!
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.white
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: self.view.frame.size.height))
webView.navigationDelegate = self
webView.scrollView.delegate = self
self.view.addSubview(webView)
let url = URL(string: "https://google.com")
webView.load(URLRequest(url: url!))
}
}
I expect to keep the large title bar visible at first screen, and only collapse when scrolling up event triggered.
Any idea?
The reason of this issue is your navigationBar height is changing when you webView starts loading the page. so using viewLayoutMarginsDidChange() we can change navigationBar height.
viewLayoutMarginsDidChange() Called to notify the view controller that the layout margins of its root view changed. This method will get called every time when navigationBar height changes.
Refer This Answer https://stackoverflow.com/a/57430695/7301439
i'm trying to use imageSlideShow cocoapods i install it and try the demo and work fine , also used it in test project and works fine , but when i used it in my project page indicator not work and i try every thing but also not working and i create a new view controller in my project and make it init and run also not work
this is my code
import UIKit
import ImageSlideshow
class test: UIViewController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .portrait
}
#IBOutlet var slideshow: ImageSlideshow!
let localSource = [ImageSource(imageString: "imageLoading")!,ImageSource(imageString: "imageLoading")!,ImageSource(imageString: "logo")!]
override func viewDidLoad() {
super.viewDidLoad()
slideshow.slideshowInterval = 5.0
slideshow.pageIndicatorPosition = .init(horizontal: .center, vertical: .customUnder(padding: 50))
slideshow.contentScaleMode = UIViewContentMode.scaleAspectFill
let pageControl = UIPageControl()
pageControl.currentPageIndicatorTintColor = UIColor.lightGray
pageControl.pageIndicatorTintColor = UIColor.black
slideshow.pageIndicator = pageControl
// optional way to show activity indicator during image load (skipping the line will show no activity indicator)
slideshow.activityIndicator = DefaultActivityIndicator()
slideshow.currentPageChanged = { page in
print("current page:", page)
}
// can be used with other sample sources as `afNetworkingSource`, `alamofireSource` or `sdWebImageSource` or `kingfisherSource`
slideshow.setImageInputs(localSource)
let recognizer = UITapGestureRecognizer(target: self, action: #selector(test.didTap))
slideshow.addGestureRecognizer(recognizer)
}
// guard let im = imageUrlString else {return "hello "}
let recognizer = UITapGestureRecognizer(target: self, action: #selector(test.didTap))
slideshow.addGestureRecognizer(recognizer)*/
}
#objc func didTap() {
let fullScreenController = slideshow.presentFullScreenController(from: self)
// set the activity indicator for full screen controller (skipping the line will show no activity indicator)
fullScreenController.slideshow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil)
}
}
and the result of that code make slide show but indicator not work it appear but not stretched and swapping correctly and as i marked in picture just color change and image but not clear number of image or any thing
https://drive.google.com/file/d/1z2pQ0HFUQC0F0oyajo9gRHOLcqsU4_sJ/view?usp=sharing
Looks like UIPageControl frame not set. If you remove all about pageControl - it will automatically place controls. Or you can create your own in storyboard:
#IBOutlet weak var imageSlideshow: ImageSlideshow!
#IBOutlet weak var slideshowPageControl: UIPageControl!
var slideshowInputs: [InputSource] {
let place = categoryPlaces[selectedIndex]
return [
... your inputs
]
}
func setupData(){
imageSlideshow.setImageInputs(slideshowInputs)
slideshowPageControl.numberOfPages = slideshowInputs.count
imageSlideshow.currentPageChanged = { page in
self.slideshowPageControl.currentPage = page
}
}
photoList is yours photos Model list,
import ImageSlideshow
.....
#IBOutlet weak var slideshowPageControl: UIPageControl!
#IBOutlet weak var slideShow: ImageSlideshow!
.....
func initslideShow()
{
var photos = [KingfisherSource]()
for item photoList {
photos.append(KingfisherSource(urlString: item.photoUrl)!)
}
slideShow.setImageInputs(photos)
let pageIndicator = UIPageControl()
pageIndicator.currentPageIndicatorTintColor = StyleManager.colors.colorPrimary
pageIndicator.pageIndicatorTintColor = StyleManager.colors.lightGray
slideShow.pageIndicator = pageIndicator
slideShow.activityIndicator = DefaultActivityIndicator(style: .white, color: nil)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(didTap))
slideShow.addGestureRecognizer(gestureRecognizer)
slideShow.zoomEnabled = true
slideShow.contentScaleMode = .scaleAspectFill
slideShow.pageIndicatorPosition = PageIndicatorPosition(horizontal: .left(padding: 20), vertical: .bottom)
slideshowPageControl.numberOfPages = photoList.count
slideShow.currentPageChanged = { page in
self.slideshowPageControl.currentPage = page
}
}
#objc func didTap() {
slideShow.presentFullScreenController(from: self)
}
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 am new to IOS. I am trying to implement activity indicator while loading web view, but I am unable to do that.While debugging I encounter that animator is starting but it is not getting visible. I am using swift 3. Here my code is as below.Please let me know what I am doing wrong. If anyone have good resource to learn about activity indicator please mention that also.
class ViewController: UIViewController,UIWebViewDelegate {
var WebView: UIWebView!
override func viewDidLoad()
{
super.viewDidLoad()
WebView = UIWebView(frame: UIScreen.main.bounds)
WebView.delegate = self
view.addSubview(WebView)
if let url = URL(string: "https://apple.com")
{
let request = URLRequest(url: url)
WebView.loadRequest(request)
}
activityindicator.startAnimating()
activityindicator.color = UIColor.black
activityindicator.alpha = 1
activityindicator.isHidden = false
}
// weak var activityindicator: UIActivityIndicatorView!
let activityindicator = UIActivityIndicatorView()
func webViewDidStartLoad(_ webView: UIWebView)
{
activityindicator.startAnimating()
activityindicator.color = UIColor.black
activityindicator.alpha = 1
activityindicator.isHidden = false
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = false
activityindicator.stopAnimating()
activityindicator.alpha = 0
activityindicator.isHidden = true
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError)
{
activityindicator.isHidden = true
}
}
Looks like the activity indicator is not added to view. Similar to how we are adding webview, center and add the indicator in viewDidLoad (code below).
activityindicator.center = self.view.center
view.addSubview(activityindicator)
Also I would suggest moving the global declarations to one place. i.e move the indicator declaration let activityindicator = UIActivityIndicatorView(), to be below webview's on top, instead of middle of class. This helps in quick readability.
Here is your full code. Now it's working -
import UIKit
class ViewController: UIViewController,UIWebViewDelegate {
var WebView: UIWebView!
override func viewDidLoad()
{
super.viewDidLoad()
WebView = UIWebView(frame: UIScreen.main.bounds)
WebView.delegate = self
view.addSubview(WebView)
if let url = URL(string: "https://apple.com")
{
let request = URLRequest(url: url)
WebView.loadRequest(request)
}
activityindicator.startAnimating()
activityindicator.center = self.view.center
view.addSubview(activityindicator)
activityindicator.color = UIColor.black
activityindicator.alpha = 1
}
// weak var activityindicator: UIActivityIndicatorView!
let activityindicator = UIActivityIndicatorView()
func webViewDidStartLoad(_ webView: UIWebView)
{
activityindicator.startAnimating()
activityindicator.color = UIColor.black
activityindicator.alpha = 1
activityindicator.isHidden = false
UIApplication.shared.isNetworkActivityIndicatorVisible = true
}
func webViewDidFinishLoad(_ webView: UIWebView)
{
UIApplication.shared.isNetworkActivityIndicatorVisible = false
activityindicator.stopAnimating()
activityindicator.alpha = 0
activityindicator.isHidden = true
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError)
{
activityindicator.isHidden = true
}
}
I'm working on a webView based screen and I want to have an activity indicator to spin while the web content is loading.
Since I have to use the same activity indicator in another screen of the app, I've put the code in static functions in a specific file.
The activity indicator seems to work fine for some web (simple) web pages but I have an issue when I load more complex pages. The activity indicators gets duplicate several times. (See screenshot below)
On the screenshot, the first activity indicator has the correct layout but the one below is darker which implies that several other activity indicators have been overlaid on top of each other. And then they never disappears.
When it comes to code:
I have a webView and two delegate methods controlling the activity indicators.
func webViewDidStartLoad(_ webView: UIWebView) {
DispatchQueue.main.async {
EBUtil.startActivityIndicator(self)
}
}
func webViewDidFinishLoad(_ webView: UIWebView) {
DispatchQueue.main.async {
EBUtil.stopActivityIndicator(self)
}
}
I guess it comes from the fact that webViewDidStartLoad gets called several times. Any idea how I can prevent this behaviour to happen?
Thanks in advance.
Edouard
EDIT:
Here is the full code for my VC.
class NewsDetailsViewController: UIViewController, UIWebViewDelegate {
//MARK: - #IBOUTLETS
#IBOutlet weak var webView: UIWebView!
//MARK: - VARIABLES
var url: String!
//MARK: - APP LIFE CYCLE
override func viewDidLoad() {
super.viewDidLoad()
if url != nil {
let urlToLoad = NSURL(string: url)
webView.loadRequest(NSURLRequest(url: urlToLoad as! URL) as URLRequest)
}
}
func webViewDidStartLoad(_ webView: UIWebView) {
DispatchQueue.main.async {
EBUtil.startActivityIndicator(self)
}
}
func webViewDidFinishLoad(_ webView: UIWebView) {
DispatchQueue.main.async {
EBUtil.stopActivityIndicator(self)
}
}
}
And code for activity indicator start and stop:
static func startActivityIndicator(_ sender: UIViewController) {
print("START ANIMATING")
if let view = sender.view {
activityIndicatorBackground = UIView(frame: CGRect(x: view.center.x - 25, y: view.center.y - 25, width: 50, height: 50))
activityIndicatorBackground.backgroundColor = UIColor.black
activityIndicatorBackground.layer.zPosition = CGFloat(MAXFLOAT-1)
activityIndicatorBackground.alpha = 0.6
activityIndicatorBackground.layer.cornerRadius = 5
view.addSubview(activityIndicatorBackground)
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
activityIndicator.center = view.center
activityIndicator.hidesWhenStopped = true
activityIndicator.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.white
activityIndicator.layer.zPosition = CGFloat(MAXFLOAT)
view.addSubview(activityIndicator)
activityIndicator.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
}
}
static func stopActivityIndicator(_ sender: UIViewController) {
print("STOP ANIMATING")
activityIndicatorBackground.removeFromSuperview()
activityIndicator.stopAnimating()
UIApplication.shared.endIgnoringInteractionEvents()
}
try this -
add below line in your viewController class -
var activityIndicator: UIActivityIndicatorView?
And update your startActivityIndicator stopActivityIndicator method like below-
func startActivityIndicator(_ sender: UIViewController) {
print("START ANIMATING")
if let view = sender.view {
if activityIndicator != nil {
activityIndicator?.removeFromSuperview()
}
activityIndicator = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
activityIndicator?.center = view.center
activityIndicator?.layer.cornerRadius = 10
activityIndicator?.backgroundColor = UIColor.gray
activityIndicator?.hidesWhenStopped = true
activityIndicator?.activityIndicatorViewStyle = UIActivityIndicatorViewStyle.white
activityIndicator?.layer.zPosition = CGFloat(MAXFLOAT)
view.addSubview(activityIndicator!)
activityIndicator?.startAnimating()
UIApplication.shared.beginIgnoringInteractionEvents()
}
}
func stopActivityIndicator(_ sender: UIViewController) {
print("STOP ANIMATING")
activityIndicator?.stopAnimating()
activityIndicator?.removeFromSuperview()
UIApplication.shared.endIgnoringInteractionEvents()
}
Hope it will work for you :)