Setting Container Controller (Root View Controller) as Delegate for View Controllers in UITabBarController - uitabbarcontroller

I'm trying to set a Container Controller (Root View Controller) as the delegate for a Nav Bar Item for a View Controller in a Tab Bar Controller and cannot figure out how to do this without using:
let rootViewController = UIApplication.shared.keyWindow?.rootViewController
This code works as I'd like it to:
let rootViewController = UIApplication.shared.keyWindow?.rootViewController
guard let doghouseViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DoghouseVC") as? DoghouseViewController else { return }
doghouseViewController.delegate = rootViewController as? DoghouseViewControllerDelegate
let nav1 = UINavigationController(rootViewController: doghouseViewController)
guard let statsViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "StatsVC") as? StatsViewController else { return }
statsViewController.delegate = rootViewController as? StatsViewControllerDelegate
let nav2 = UINavigationController(rootViewController: statsViewController)
dailyWrapUpViewController = DailyWrapUpViewController()
guard let calendarViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CalendarVC") as? CalendarViewController else { return }
calendarViewController.delegate = rootViewController as? CalendarViewControllerDelegate
let nav3 = UINavigationController(rootViewController: calendarViewController)
guard let settingsViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SettingsVC") as? SettingsViewController else { return }
settingsViewController.delegate = rootViewController as? SettingsViewControllerDelegate
let nav4 = UINavigationController(rootViewController: settingsViewController)
doghouseViewController.tabBarItem = UITabBarItem(title: "Doghouse", image: UIImage(named: "doghouse"), tag: 0)
statsViewController.tabBarItem = UITabBarItem(title: "Stats", image: UIImage(named: "stats"), tag: 1)
// Custom Doggy Bag Button
let controller2 = UIViewController()
calendarViewController.tabBarItem = UITabBarItem(title: "Calendar", image: UIImage(named: "calendar"), tag: 3)
settingsViewController.tabBarItem = UITabBarItem(title: "More", image: UIImage(named: "more"), tag: 4)
viewControllers = [nav1, nav2, controller2, nav3, nav4]
// Use the view controller reference to select the second tab
selectedViewController = nav1
But, 'keyWindow' was deprecated in iOS 13.0 and if I try to change it using the following as an example, the delegate functionality doesn't work (button gets pushed, but Container Controller instance does not receive):
let rootViewController = UIApplication.shared.windows.first!.rootViewController as! ContainerController
For more context, the Container Controller (Root View Controller) is a side menu that slides out on the tap of a NavBar Item within the TabBarController.
How do I solve this?

Figured it out:
let sceneDelegate = UIApplication.shared.connectedScenes.first!.delegate as! SceneDelegate
guard let doghouseViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DoghouseVC") as? DoghouseViewController else { return }
doghouseViewController.delegate = sceneDelegate.window!.rootViewController as? DoghouseViewControllerDelegate
let nav1 = UINavigationController(rootViewController: doghouseViewController)
guard let statsViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "StatsVC") as? StatsViewController else { return }
statsViewController.delegate = sceneDelegate.window!.rootViewController as? StatsViewControllerDelegate
let nav2 = UINavigationController(rootViewController: statsViewController)
dailyWrapUpViewController = DailyWrapUpViewController()
guard let calendarViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "CalendarVC") as? CalendarViewController else { return }
calendarViewController.delegate = sceneDelegate.window!.rootViewController as? CalendarViewControllerDelegate
let nav3 = UINavigationController(rootViewController: calendarViewController)
guard let settingsViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SettingsVC") as? SettingsViewController else { return }
settingsViewController.delegate = sceneDelegate.window!.rootViewController as? SettingsViewControllerDelegate
let nav4 = UINavigationController(rootViewController: settingsViewController)
doghouseViewController.tabBarItem = UITabBarItem(title: "Doghouse", image: UIImage(named: "doghouse"), tag: 0)
statsViewController.tabBarItem = UITabBarItem(title: "Stats", image: UIImage(named: "stats"), tag: 1)
// Custom Doggy Bag Button
let controller2 = UIViewController()
calendarViewController.tabBarItem = UITabBarItem(title: "Calendar", image: UIImage(named: "calendar"), tag: 3)
settingsViewController.tabBarItem = UITabBarItem(title: "More", image: UIImage(named: "more"), tag: 4)
viewControllers = [nav1, nav2, controller2, nav3, nav4]
// Use the view controller reference to select the second tab
selectedViewController = nav1

Related

Xcode SwiftUI Sharing custom image is blank

I am trying to allow my user to share an image with an overlay via text or social media.
I am successfully creating an image (I know because it shows up in the photos album) using the following extension:
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
When I ‘share’, it acknowledges the image is there (the share sheet changes its options) but the image is either not there or it is an empty white square.
I call it like this:
let myImage = textView.snapshot() //uses the snapshot extension above
ShareSheet(activityItems: ["my app name", myImage])
struct ShareSheet: UIViewControllerRepresentable {
typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void
let activityItems: [Any]
let applicationActivities: [UIActivity]? = nil
let excludedActivityTypes: [UIActivity.ActivityType]? = nil ///[.postToFacebook] //nil
let callback: Callback? = nil
func makeUIViewController(context: Context) -> UIActivityViewController {
let controller = UIActivityViewController(
activityItems: activityItems,
applicationActivities: applicationActivities)
controller.excludedActivityTypes = excludedActivityTypes
controller.completionWithItemsHandler = callback
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
// nothing to do here
}
}
I know this is not an answer, but since the comments are very limited,
I'm posting some code that may help find why it does not work for you.
For me it seems work, on macos 12.beta5, xcode 13.beta5, target ios 15 and macCatalyst. This is the code I used in my test:
import Foundation
import SwiftUI
import UIKit
import MobileCoreServices
#main
struct TestApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
struct ContentView: View {
#State var shareIt = false
#State var myImage = UIImage(systemName: "globe")
var body: some View {
VStack (spacing: 55) {
Image(uiImage: myImage!).resizable().frame(width: 222, height: 222)
Button(action: {
myImage = snapshot()
shareIt = true
}) {
Text("Click to share")
}
.sheet(isPresented: $shareIt, onDismiss: {shareIt = false}) {
ShareSheet(activityItems: [myImage as Any])
}
}
}
}
extension View {
func snapshot() -> UIImage {
let controller = UIHostingController(rootView: self)
let view = controller.view
let targetSize = controller.view.intrinsicContentSize
view?.bounds = CGRect(origin: .zero, size: targetSize)
view?.backgroundColor = .clear
let renderer = UIGraphicsImageRenderer(size: targetSize)
return renderer.image { _ in
view?.drawHierarchy(in: controller.view.bounds, afterScreenUpdates: true)
}
}
}
struct ShareSheet: UIViewControllerRepresentable {
typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void
let activityItems: [Any]
let applicationActivities: [UIActivity]? = nil
let excludedActivityTypes: [UIActivity.ActivityType]? = nil ///[.postToFacebook] //nil
let callback: Callback? = nil
func makeUIViewController(context: Context) -> UIActivityViewController {
let controller = UIActivityViewController(
activityItems: activityItems,
applicationActivities: applicationActivities)
controller.excludedActivityTypes = excludedActivityTypes
controller.completionWithItemsHandler = callback
return controller
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) { }
}

Presenting view controllers on detached view controllers is discouraged (with SWRevealViewController)

I am changing the RootViewController of SwRevealViewController
My code:
let next = self.storyboard?.instantiateViewController(withIdentifier: "SWRevealViewController") as! SWRevealViewController
next.loadView()
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let viewController = mainStoryboard.instantiateViewController(withIdentifier: "MessageViewController") as! MessageViewController
UIApplication.shared.keyWindow?.rootViewController = viewController;
self.present(next, animated: true, completion: nil)
But I get this error:
>Presenting view controllers on detached view controllers is discouraged <ios.MesajDetayViewController: 0x7f8718d646f0>.
How to solve?
solution
let sw = storyboard?.instantiateViewController(withIdentifier: "SWRevealViewController") as! SWRevealViewController
self.view.window?.rootViewController = sw
let mainStroyBoard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let desController = mainStroyBoard.instantiateViewController(withIdentifier: "MessageViewController") as! MessageViewController
let newFrontViewController = UINavigationController.init(rootViewController:desController)
sw.pushFrontViewController(newFrontViewController, animated: true)
if you want to change SWRevealViewContoller front view controller, you should use
let newFronViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "YourID") as! YourClass
self.revealViewController().setFront(newFronViewController, animated: false)
I can update my answer depending on where you would like to call this.

Tab Bar not showing when push notifications clicked and goes to a Specific ViewController in Swift 3.0?

I am receiving Push Notifications when i click on Notification i want to go to a particular ViewController opens when click i click on SlideMenu didSelectRow. I tried many SO links but below code i am able to go to a particular ViewController but problem is tabBar it not showing.
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {
let mainstoryboard = UIStoryboard(name: "Main", bundle: nil)
let ringingVC = mainstoryboard.instantiateViewController(withIdentifier: "RaffleResultViewController") as? RaffleResultViewController
window?.rootViewController = ringingVC
}
let mainstoryboard = UIStoryboard(name: "Main", bundle: nil)
let ringingVC = mainstoryboard.instantiateViewController(withIdentifier: "RaffleResultViewController") as? RaffleResultViewController
let selectedVC = window.rootViewController
if let nav = selectedVC as? UINavigationController{
nav.pushViewController(ringingVC, animated: true)
}else{
selectedVC.present(ringingVC, animated: true, completion: nil)
}
// USE this

Swift3 Play multiple video files with AVPlayer

I have a little code which allows me to play a local file when I hit a UIButton. But what I want is to play multiple files on 3 different UIButtons because I have 3 video files which I want to attach to my app.
This is the current code:
import UIKit
import AVFoundation
import AVKit
class ViewController: UIViewController {
var playerController = AVPlayerViewController()
var player:AVPlayer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let videoString:String? = Bundle.main.path(forResource: "Video", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func PlayVideo(_ sender: AnyObject) {
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}
}
You can create url for different video file in your button click funtions
#IBAction func Button1Click(_ sender: AnyObject) {
let videoString:String? = Bundle.main.path(forResource: "Video1", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}
#IBAction func Button2Click(_ sender: AnyObject) {
let videoString:String? = Bundle.main.path(forResource: "Video2", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}
#IBAction func Button3Click(_ sender: AnyObject) {
let videoString:String? = Bundle.main.path(forResource: "Video3", ofType: ".mp4")
if let url = videoString {
let videoURL = NSURL(fileURLWithPath: url)
self.player = AVPlayer(url: videoURL as URL)
self.playerController.player = self.player
}
self.present(self.playerController, animated: true, completion: {
self.playerController.player?.play()
})
}

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")
}