Swift 3 NavigationController segue back causes wkwebview to move into wrong position - swift3

I have a ViewController containing a WKWebView, the view is positioned correctly the first time it loads, but after moving to another view (I'm opening another view by intercepting links from the WebView) and pressing the navigation item (back button) it briefly appears in the right place, then reloads with the top of the webview behind the navigation bar so the top of the page is cut off.
class HomeVC: BaseViewController, WKNavigationDelegate, WKUIDelegate {
var webView: WKWebView?
override func viewDidAppear(_ animated: Bool) {
self.edgesForExtendedLayout = UIRectEdge.top;
super.viewDidLoad()
addSlideMenuButton()
let screenSize: CGRect = UIScreen.main.bounds
let frameRect: CGRect = CGRect(x: 0, y: 100, width: screenSize.width, height: screenSize.height)
let url: NSURL = Bundle.main.url(forResource: "services", withExtension: "html")! as NSURL
let requestObj: NSURLRequest = NSURLRequest(url: url as URL);
self.webView = WKWebView(frame: frameRect)
self.webView?.load(requestObj as URLRequest)
self.webView?.navigationDelegate = self
self.webView?.uiDelegate = self
self.view = self.webView
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationItem.title = ""
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.navigationItem.title = "SELECT A SERVICE"
}
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
let link: String = (webView.url?.absoluteString)!
print(link)
if(link == "file:///haircut") {
print(link)
self.openViewControllerBasedOnIdentifier("WebVC")
}
}
I've searched around and can't find any similar issues, nor can I see anything obvious in the code.

You have are calling super.viewDidLoad from func viewDidAppear(), what can cause unexpected behaviour. Therefore your UIViewController subclass will never notify its superclass, that the view has been loaded.
override func viewDidAppear(_ animated: Bool) {
// Do not do this before calling super!
self.edgesForExtendedLayout = UIRectEdge.top;
// You are calling the wrong the function for super
// It should be super.viewDidAppear(animated)
super.viewDidLoad()
addSlideMenuButton()
let screenSize: CGRect = UIScreen.main.bounds
let frameRect: CGRect = CGRect(x: 0, y: 100, width: screenSize.width, height: screenSize.height)
let url: NSURL = Bundle.main.url(forResource: "services", withExtension: "html")! as NSURL
let requestObj: NSURLRequest = NSURLRequest(url: url as URL);
self.webView = WKWebView(frame: frameRect)
self.webView?.load(requestObj as URLRequest)
self.webView?.navigationDelegate = self
self.webView?.uiDelegate = self
self.view = self.webView
}

Related

Can't Turn UIKit Into Swift UI With UIViewRepresentable

I have followed two tutorials on UIViewRepresentable and thought the following would work, yet it didn't and I think my situation is more complex than in the tutorials.
Hello, I am trying to turn this code
import SpriteKit
import AVFoundation
class ViewController: NSViewController {
#IBOutlet var skView: SKView!
var videoPlayer: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.skView {
// Load the SKScene from 'backgroundScene.sks'
guard let scene = SKScene(fileNamed: "backgroundScene") else {
print ("Could not create a background scene")
return
}
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
// Add the video node
guard let alphaMovieURL = Bundle.main.url(forResource: "camera_city_animated", withExtension: "mov") else {
print("Failed to overlay alpha movie on the background")
return
}
videoPlayer = AVPlayer(url: alphaMovieURL)
let video = SKVideoNode(avPlayer: videoPlayer)
video.size = CGSize(width: view.frame.width, height: view.frame.height)
print( "Video size is %f x %f", video.size.width, video.size.height)
scene.addChild(video)
// Play video
videoPlayer.play()
videoPlayer?.actionAtItemEnd = .none
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: videoPlayer?.currentItem)
}
}
#objc func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: CMTime.zero, completionHandler: nil)
}
}
}
Into a SwiftUI View by placing it inside the func makeUIView(context: Context) -> UITextView {} of my struct TransparentVideoLoop: UIViewRepresentable {} struct.
What am I missing?
Full code:
struct TransparentVideoLoop: UIViewRepresentable {
func makeUIView(context: Context) -> UITextView {
#IBOutlet var skView: SKView!
var videoPlayer: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.skView {
// Load the SKScene from 'backgroundScene.sks'
guard let scene = SKScene(fileNamed: "backgroundScene") else {
print ("Could not create a background scene")
return
}
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
// Present the scene
view.presentScene(scene)
// Add the video node
guard let alphaMovieURL = Bundle.main.url(forResource: "camera_city_animated", withExtension: "mov") else {
print("Failed to overlay alpha movie on the background")
return
}
videoPlayer = AVPlayer(url: alphaMovieURL)
let video = SKVideoNode(avPlayer: videoPlayer)
video.size = CGSize(width: view.frame.width, height: view.frame.height)
print( "Video size is %f x %f", video.size.width, video.size.height)
scene.addChild(video)
// Play video
videoPlayer.play()
videoPlayer?.actionAtItemEnd = .none
NotificationCenter.default.addObserver(self,
selector: #selector(playerItemDidReachEnd(notification:)),
name: .AVPlayerItemDidPlayToEndTime,
object: videoPlayer?.currentItem)
}
}
#objc func playerItemDidReachEnd(notification: Notification) {
if let playerItem = notification.object as? AVPlayerItem {
playerItem.seek(to: CMTime.zero, completionHandler: nil)
}
}
}
func updateUIView(_ uiView: UITextView, context: Context) {
}
}
I have to return the view, but this is more complex than in the tutorials.
Use UIViewControllerRepresentable instead, e.g.
import SwiftUI
struct ImagePicker: UIViewControllerRepresentable {
#Binding var selectedImage: UIImage?
#Environment(\.presentationMode) var presentationMode
func makeCoordinator() -> ImagePicker.Coordinator {
Coordinator()
}
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {}
func makeUIViewController(context: Context) -> some UIViewController {
context.coordinator.imagePicker
}
final class Coordinator: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
lazy var imagePicker: UIImagePickerController = {
let imagePickerController = UIImagePickerController()
imagePickerController.sourceType = .photoLibrary
imagePickerController.delegate = self
return imagePickerController
}()
var imageSelected: ((UIImage) -> Void)?
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
DispatchQueue.main.async {
if let selectedImage = (info[.editedImage] ?? info[.originalImage]) as? UIImage {
imageSelected?(selectedImage)
}
//self.parent.presentationMode.wrappedValue.dismiss()
}
}
}
}
Note this is inspired by ImagePicker.swift from an Apple sample but the developer got the Coordinator wrong so I have corrected that. It also needs the update func fixed.

Disable horizontal scrolling for WKWebView

I know how to do this for UIWebView, but it is deprecated. I have figured out how to hide both the vertical and horizontal scroll indicators, disable scrollview bounces and disable the pinch gesture recognizer but still haven't found a way to wholly disable horizontal scrolling in the webview. Any help would be appreciated, below is my WebView.Swift.
struct WebView: UIViewRepresentable
{
let request: URLRequest
var webView: WKWebView?
init (request: URLRequest)
{
self.webView = WKWebView()
self.request = request
webView?.scrollView.showsHorizontalScrollIndicator = false
webView?.scrollView.showsVerticalScrollIndicator = false
webView?.scrollView.pinchGestureRecognizer?.isEnabled = false
webView?.scrollView.bounces = false
}
func makeUIView(context: Context) -> WKWebView {
return webView!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(request)
}
func goBack()
{
webView?.goBack()
}
func refresh()
{
webView?.reload()
}
func goHome()
{
webView?.load(request)
}
}
For this, you may use Coordinator. There is good explanation for their.
Create class Coordinator in your UIViewRepresentable. Add UIScrollViewDelegate to class. In makeUIView, set webView?.scrollView.delegate = context.coordinator.
In Coordinator, you need this function.
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.x > 0){
scrollView.contentOffset = CGPoint(x: 0, y: scrollView.contentOffset.y)
}
}
And now, horizontal scroll not work!
All code
import WebKit
struct WebView: UIViewRepresentable {
let request: URLRequest
var webView: WKWebView?
class Coordinator: NSObject, UIScrollViewDelegate {
var parent: WebView
init(_ parent: WebView) {
self.parent = parent
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if (scrollView.contentOffset.x > 0){
scrollView.contentOffset = CGPoint(x: 0, y: scrollView.contentOffset.y)
}
}
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
init (request: URLRequest) {
self.webView = WKWebView()
self.request = request
webView?.scrollView.showsHorizontalScrollIndicator = false
webView?.scrollView.showsVerticalScrollIndicator = false
webView?.scrollView.pinchGestureRecognizer?.isEnabled = false
webView?.scrollView.bounces = false
}
func makeUIView(context: Context) -> WKWebView {
webView?.scrollView.delegate = context.coordinator
return webView!
}
func updateUIView(_ uiView: WKWebView, context: Context) {
uiView.load(request)
}
// You funcs
}

How to navigate to different storyboards along with sidemenu in swift 3

I am using third party control for sidemenu named : MMDrawerController, and m handling UI using multiple storyboards.let me come to the point my sidemenu looks like this : Sidemenu Image
Trying to achieve :
1)When I click on the Parent, "main.storyboard" should be displayed.
2)When I click on the Management, "management.storyboard" should be displayed.
same sidemenu should be displayed across all storyboard file.
I have tried some code by my own but m not getting the sidemenu on "management.storyboard" :(
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch(indexPath.row)
{
case 4:
let mainstoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var welview = mainstoryboard.instantiateViewController(withIdentifier: "WelcomeParentViewController") as! WelcomeParentViewController
var welnav = UINavigationController(rootViewController: welview)
var appdel : AppDelegate = UIApplication.shared.delegate as! AppDelegate
appdel.centerContainer!.centerViewController = welnav
appdel.centerContainer!.toggle(MMDrawerSide.left, animated: true, completion: nil)
break
case 5:
let mainstoryboard : UIStoryboard = UIStoryboard(name: "Management-Storyboard", bundle: nil)
var welview = mainstoryboard.instantiateViewController(withIdentifier: "ReportsViewController") as! ReportsViewController
var welnav = UINavigationController(rootViewController: welview)
var appdel : AppDelegate = UIApplication.shared.delegate as! AppDelegate
appdel.centerContainer!.centerViewController = welnav
appdel.centerContainer!.toggle(MMDrawerSide.left, animated: true, completion: nil)
break
default :
break
}
I want same sidemenu across all storyboard file.
how to accomplish the above feature.Please Help.Thank you in advance.
MMDrawerController Code inside the appdelegate.swift
import UIKit
import GoogleMaps
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var centerContainer : MMDrawerController?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
if isUserLoggedIn()
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.gotoMainvc()
}
else
{
let rootViewController = self.window!.rootViewController
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let setViewController = mainStoryboard.instantiateViewController(withIdentifier: "LoginViewController") as! LoginViewController
rootViewController?.navigationController?.popToViewController(setViewController, animated: false)
}
return true
}
func isUserLoggedIn() -> Bool{
if let accessToken = UserDefaults.standard.object(forKey: "access_token") as? String
{
if (accessToken.characters.count) > 0{
return true
} else {
return false
}
}
else {
return false
}
}
func gotoMainvc()
{
var rootviewcontroller = self.window?.rootViewController
if(UIDevice.current.userInterfaceIdiom == .phone)
{
let mainstoryboard : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var centerviewcontroller = mainstoryboard.instantiateViewController(withIdentifier: "WelcomeParentViewController") as! WelcomeParentViewController
var leftsideviewcontroller = mainstoryboard.instantiateViewController(withIdentifier: "LeftSideMenuViewController") as! LeftSideMenuViewController
let leftsidenav = UINavigationController(rootViewController: leftsideviewcontroller)
let centernav = UINavigationController(rootViewController: centerviewcontroller)
centerContainer = MMDrawerController(center: centernav, leftDrawerViewController: leftsidenav)
centerContainer?.openDrawerGestureModeMask = MMOpenDrawerGestureMode.panningCenterView
centerContainer?.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.panningCenterView
window?.rootViewController = centerContainer
window?.makeKeyAndVisible()
}
else{
let mainstoryboard2 : UIStoryboard = UIStoryboard(name: "Storyboard-iPad", bundle: nil)
var centerviewcontroller = mainstoryboard2.instantiateViewController(withIdentifier: "WelcomeParentViewController") as! WelcomeParentViewController
var leftsideviewcontroller = mainstoryboard2.instantiateViewController(withIdentifier: "LeftSideMenuViewController") as! LeftSideMenuViewController
let leftsidenav = UINavigationController(rootViewController: leftsideviewcontroller)
let centernav = UINavigationController(rootViewController: centerviewcontroller)
centerContainer = MMDrawerController(center: centernav, leftDrawerViewController: leftsidenav)
centerContainer?.openDrawerGestureModeMask = MMOpenDrawerGestureMode.panningCenterView
centerContainer?.closeDrawerGestureModeMask = MMCloseDrawerGestureMode.panningCenterView
window?.rootViewController = centerContainer
window?.makeKeyAndVisible()
}
}
//MARK: sharedDelegate
func sharedDelegate() -> AppDelegate
{
return UIApplication.shared.delegate as! AppDelegate
}
}
Main View Controller
import UIKit
class ViewController: UIViewController , UICollectionViewDelegate , UICollectionViewDataSource , UIGestureRecognizerDelegate {
#IBOutlet weak var collectioncell: UICollectionView!
var objectProfile:SideMenuViewController!
var tapGesture = UITapGestureRecognizer()
override func viewDidLoad() {
super.viewDidLoad()
tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.myviewTapped(_:)))
tapGesture.numberOfTapsRequired = 1
tapGesture.numberOfTouchesRequired = 1
collectioncell.addGestureRecognizer(tapGesture)
collectioncell.isUserInteractionEnabled = true
let storyboard = UIStoryboard(name: "Main", bundle: nil)
self.objectProfile = storyboard.instantiateViewController(withIdentifier: "SideMenuViewController") as! SideMenuViewController
self.objectProfile.view.frame = CGRect(x: -(self.view.frame.size.width - 40), y: 0, width: self.view.frame.size.width - 40, height: self.view.frame.size.height)
self.view.addSubview(self.objectProfile.view)
self.navigationController?.didMove(toParentViewController: self.objectProfile)
self.collectioncell.layer.cornerRadius = 5.0
self.collectioncell.layer.borderWidth = 5.0
self.collectioncell.clipsToBounds = true
self.collectioncell.layer.borderColor = UIColor.clear.cgColor
self.collectioncell.layer.masksToBounds = true
}
func myviewTapped(_ sender: UITapGestureRecognizer) {
if self.objectProfile.view.isHidden == false {
UIView.animate(withDuration: 0.3)
{
self.objectProfile.view.frame = CGRect(x: -(self.view.frame.size.width - 90), y: 0, width: self.view.frame.size.width - 90, height: self.view.frame.size.height)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func Mrnupressed(_ sender: UIBarButtonItem) {
UIView.animate(withDuration: 0.3)
{
self.objectProfile.view.frame = CGRect(x: 0 , y: 0, width: (self.view.frame.size.width - 100), height: self.view.frame.size.height)
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return 6
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionCell", for: indexPath) as! MainCollectionViewCell
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize {
let cellsize = CGSize(width: (collectioncell.bounds.size.width/2) - 12, height:(collectioncell.bounds.size.height/3) - 20)
return cellsize
}
}
Child View Controller
import UIKit
class SideMenuViewController: UIViewController,UITableViewDelegate, UITableViewDataSource {
#IBOutlet weak var sidemenutable: UITableView!
var stri:String!
var ArrarMenu:[String] = ["Home","SiteMep","Student","About Us","Help"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return ArrarMenu.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SideMenuCell") as! SideMenuTableViewCell
let objarray = ArrarMenu[indexPath.row]
cell.lblitem.text = objarray
stri = objarray
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == 0{
self.performSegue(withIdentifier: "SegueForHome", sender: self)
}
}
}
In This Code I Am use Child View As Side Manu Controller
here is code open side from other storyboard
#IBAction func menutapped(_ sender: Any) {
var appdelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
appdelegate.centerContainer?.toggle(MMDrawerSide.left, animated: true, completion: nil)
}

Swift Hides back button

I want to hide the back button and set a title.
I'm using the following code:
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Einstellungen"
navigationItem.hidesBackButton = true }
But the title isn't shown and the back button is still there but if I touch it nothing happens. Can anybody help me please?
I found a solution on my own.
If I'm setting the title and the hidesBackButton from my previous ViewController everything works fine.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destinationVC = segue.destination as? ViewControllerFirstSettings {
destinationVC.navigationItem.hidesBackButton = true
destinationVC.navigationItem.title = "Einstellungen"
}
}
This code may help :
// MARK: - CUSTOM METHODS
func createNavBar() {
let leftNavigationButton = UIButton()
leftNavigationButton.setImage(UIImage(named: "ic_back.png"), forState: .Normal)
leftNavigationButton.frame = CGRectMake(10, 10, 20, 15)
leftNavigationButton.addTarget(self, action: "onBackButtonPressed:", forControlEvents: UIControlEvents.TouchUpInside)
let customBarItem = UIBarButtonItem(customView: leftNavigationButton)
self.navigationItem.leftBarButtonItem = customBarItem;
//set TitleAppIcon
let GR = UITapGestureRecognizer(target: self, action: Selector("headerLogoTapAction:"))
let imageView = UIImageView(frame: CGRect(x: 90, y: 0, width: ((UIScreen.mainScreen().bounds.width)/3), height: 40))
imageView.addGestureRecognizer(GR)
imageView.userInteractionEnabled = true
navigationItem.titleView = imageView
}

Avplayer is not playing with swift 3 (Xcode 8)

please help me log is shown playing but no sound is heard
let url = URL(string: "https://s3.amazonaws.com/kargopolov/BlueCafe.mp3")
let playerItem = AVPlayerItem(url: url! as URL)
let player=AVPlayer(playerItem: playerItem)
player.volume=1.0
player.play()
if (player.rate != 0 && player.error == nil) {
print("playing")
}
else
{
print("error",player.error)
}
You need a to assign the player to a variable that doesn't go out of scope, eg
class ViewControllerA: UIViewController {
var avPlayer: AVPlayer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view
}
override func viewDidAppear(_ animated: Bool) {
let videoURL = NSURL(string: "https://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4")
avPlayer = AVPlayer(url: videoURL! as URL)
let playerLayer = AVPlayerLayer(player: avPlayer)
playerLayer.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width * 3.0 / 4.0)
self.view.layer.addSublayer(playerLayer)
avPlayer.play()
}
}
Declare Player Variable before
var playerT : AVPlayer!
Now you able to play song from url
let url = URL(string: "https://s3.amazonaws.com/kargopolov/BlueCafe.mp3")
playerT = AVPlayer(url: url!)
playerT.volume = 1.0
playerT.play()
if playerT.rate != 0 && playerT.error == nil{
print("Playing")
}else{
print("Error Playing")
}