Tab Bar not appearing on applicationDidBecomeActive - ios

Requirement - When user open Application from the background tabBar selected index should be 2
What i tried -
//For getting current visible controller -
public extension UIWindow {
public var visibleViewController: UIViewController? {
return UIWindow.getVisibleViewControllerFrom(self.rootViewController)
}
public static func getVisibleViewControllerFrom(_ vc: UIViewController?) -> UIViewController? {
if let nc = vc as? UINavigationController {
return UIWindow.getVisibleViewControllerFrom(nc.visibleViewController)
} else if let tc = vc as? UITabBarController {
return UIWindow.getVisibleViewControllerFrom(tc.selectedViewController)
} else {
if let pvc = vc?.presentedViewController {
return UIWindow.getVisibleViewControllerFrom(pvc)
} else {
return vc
}
}
}
}
let appdelegate = UIApplication.shared.delegate as! AppDelegate
//Selected 2 tabbar -
func applicationDidBecomeActive(_ application: UIApplication) {
if appdelegate.window?.visibleViewController != nil {
appdelegate.window?.visibleViewController?.hidesBottomBarWhenPushed = false
appdelegate.window?.visibleViewController?.navigationController?.popToRootViewController(animated: true)
appdelegate.window?.visibleViewController?.tabBarController?.selectedIndex = 2
appdelegate.window?.visibleViewController?.tabBarController?.tabBar.isHidden = false
appdelegate.window?.bringSubview(toFront: (appdelegate.window?.visibleViewController?.tabBarController?.view)!)
}
}
The code is working fine but problem is Tabbbar get hidden. Why?

This will work if each tab has a navigationController
if let tabController = self.window!.rootViewController as? UITabBarController {
if let navController = tabBarController.selectedViewController as? UINavigationController{
navController.popToRootViewController(animated: true)
tabBarController.selectedIndex = 2
}
}

You need to subclass UITabBarViewController
override viewWillAppear method.
Subscrib UIApplicationWillEnterForeground notification.
Set selectedIndex on notification received.
class HomeViewController: UITabBarController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(self, selector:#selector(applicationWillEnterForeground(notification:)), name: .UIApplicationWillEnterForeground, object: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.removeObserver(self, name: .UIApplicationWillEnterForeground, object: nil)
}
#objc private func applicationWillEnterForeground(notification: Notification) {
selectedIndex = 2
}}

Related

tableView.selectRow(...) doesn't work when I use UIAdaptivePresentationControllerDelegate (Swift 5)

In my app I use .present(...) to show one View Controller on top of the other (these are the same VC). When I dismiss it (pull down from screen) I want to select some row in my first VC. For it I use UIAdaptivePresentationControllerDelegate in which I have print(...) and tableView.selectRow(...) function. Print works fine, but tableView.selectRow doesn't work. What could be the issue?
extension UIViewController {
class func loadFromStoryboard<T: UIViewController>() -> T {
let name = String(describing: T.self)
let storyboard = UIStoryboard(name: name, bundle: nil)
if let viewController = storyboard.instantiateInitialViewController() as? T {
return viewController
} else {
fatalError("Error: No initial view controller in \(name) stroryboard")
}
}
}
class MyTabBarController: UITabBarController {
let firstVC: FirstVC = FirstVC.loadFromStoryboard()
...
override func viewDidLoad() {
super.viewDidLoad()
loadViewControllers()
}
private func generateViewController(rootViewController: UIViewController, image: UIImage?, title: String) -> UIViewController {
let navigationVC = UINavigationController(rootViewController: rootViewController)
...
return navigationVC
}
private func loadViewControllers() {
viewControllers = [
generateViewController(rootViewController: firstVC, image: ..., title: "...")
]
}
...
private func openVC() {
let storyboard = UIStoryboard(name: "FirstVC", bundle: nil)
let vc = storyboard.instantiateViewController(identifier: "FirstVC") as! FirstVC
vc.presentationController?.delegate = vc
self.present(vc, animated: true, completion: nil)
}
...
}
//FirstVC
extension FirstVC: UIAdaptivePresentationControllerDelegate {
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
print("VC was dismissed")
self.tableView.selectRow(at: IndexPath(row: 0, section: 0), animated: true, scrollPosition: .none)
}
}
In the console I see "VC was dismissed", but row doesn't select.
P.S. I use Xcode 12.2 and iOS 14.2.
The tableView is an IBOutlet, if it's important.
You should set:
vc.presentationController?.delegate = self
Instead of:
vc.presentationController?.delegate = vc
Because you lose delegate as soon as you dismiss vc. You should listen dismissal of FirstVC on self where you present FirstVC.
If you just miss that it's ok. But if you can't understand why I can share more details :)

Tab Controller is dismissing as well when GADRewardBasedVideoAd in AdMob dismisses

I have an ViewController with GADRewardBasedVideoAd.
I can easily play and close ads, but with the ad closes ViewController as well.
What can I do?
#IBAction func ad_button_click(_ sender: Any) {
if GADRewardBasedVideoAd.sharedInstance().isReady == true
{
GADRewardBasedVideoAd.sharedInstance().present(fromRootViewController: self)
}
}
For those of you who is facing the the same issue:
You can create a new class for your rootViewController (TabBarController or NavigationController etc.) and implement there something like that:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
dismissalCounter += 1
if (dismissalCounter < 2) {
super.dismiss(animated: flag, completion: completion)
}
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
dismissalCounter = 0
}
override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
dismissalCounter = 0
super.present(viewControllerToPresent, animated: flag, completion: completion)
}
var dismissalCounter : Int = 0
Important! Use this functions inside TabBarController or NavigationController, otherwise it is not gonna work
UPD:
In my case unfortunatly it breaks all NavigationControllers inside a TabBarController (titles don't show and there are no buttons inside them), if I will figure fix actions, I'll let you know
UPD2:
Pretty obvious decision will be to change the initialViewController and view add from it, it'll not be dismissed
UPD3:
I solved this very and very strange:
class ViewController : UIViewController {
override func viewWillAppear(_ animated: Bool) {
if GADRewardBasedVideoAd.sharedInstance().isReady == false {
let request = GADRequest()
rewardBasedVideo!.load(request, withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
}
}
var rewardBasedVideo: GADRewardBasedVideoAd?
#IBAction func ad_button_click(_ sender: Any) {
if rewardBasedVideo!.isReady == true {
let bl = blur()
self.present(bl, animated: true, completion: {
self.rewardBasedVideo?.present(fromRootViewController: bl)
})
}
}
}
class blur : UIViewController {
override func viewDidLoad() {
checkForKeyWindow()
}
func checkForKeyWindow() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
if (UIApplication.topViewController() == self) {
print("dismissed and forgotten")
self.dismiss(animated: true, completion: nil)
} else {
print("not keywindow")
self.checkForKeyWindow()
}
})
}
#objc func close() {
self.dismiss(animated: true, completion: nil)
}
}
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
let moreNavigationController = tab.moreNavigationController
if let top = moreNavigationController.topViewController, top.view.window != nil {
return topViewController(base: top)
} else if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}

Admob Rewarded video - Root view controller issue

So I have two view controllers in my application:
StartViewController (Root view controller) and GameViewController
I am presenting my Rewarded video from GameViewController
Everything works perfectly, except for when the user presses "Skip now" on the rewarded video. It dismisses GameViewController and goes back to StartViewController which is my root view controller.
If the user watches the entire video, it works as intended.
The code for presenting rewarded view from GameViewController:
func playReward()
{
if rewardVideo!.isReady
{
if var topController = UIApplication.shared.keyWindow?.rootViewController
{
while let presentedViewController = topController.presentedViewController
{
// Make top controller topmost view controller
topController = presentedViewController
}
rewardVideo!.present(fromRootViewController: topController)
}
}
}
I temporarily changed the root to GameViewController to see if this was the issue and doing so fixed it, so I know it is an issue related to the root view controller and the "Skip now" button on the rewarded video.
I had the same issue. I solved it by overriding the func dismiss(animated flag: Bool, completion: (() -> Void)? = nil method.
Here is what I did.
var didOpenRewardedVideo:Int = 0
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
if didOpenRewardedVideo == 1 {
didOpenRewardedVideo = 2
super.dismiss(animated: flag, completion: completion)
}
else if didOpenRewardedVideo == 2{
didOpenRewardedVideo = 0
}
else{
super.dismiss(animated: flag, completion: completion)
}
}
func showRewardedVideo()
{
didOpenRewardedVideo = 1
GADRewardBasedVideoAd.sharedInstance().present(fromRootViewController: self)
}
Before showing the rewardedAd, do not forget to check if it's ready or not.
GADRewardBasedVideoAd.sharedInstance().isReady == true
When rewardedAd is presented didOpenRewardedVideo is set to 1. When user dismissing rewardedAd didOpenRewardedVideo is 1 and calling super.dismiss(animated: flag, completion: completion). Then didOpenRewardedVideo is set to 2. Now I know dismiss(animated flag: Bool, completion: (() -> Void)? = nil) will be called once more. This time I don't call the super method and set didOpenRewardedVideo to 0. I know if I dismiss my UIViewController will be dismissed.
#mialkan,
your solution does not work. I don't why no one talk about this issue. I am also facing such problem.
import GoogleMobileAds import sdk in your class or viewcontroller
GADRewardBasedVideoAdDelegate Add this in your class or viewcontroller
var RewardBasedVideo: GADRewardBasedVideoAd? **initialize AdController object **
override func viewDidLoad()
{
super.viewDidLoad()
RewardBasedVideo=GADRewardBasedVideoAd.sharedInstance()
RewardBasedVideo?.delegate = self
}
//MARK:- WATCH AD BUTTON CLICK
#IBAction func WatchAdBtn_Click(_ sender: UIButton)
{
if RewardBasedVideo?.isReady == true
{
RewardBasedVideo?.present(fromRootViewController: self)
} else
{
//Show alert here "Ads is not ready to load"
}
}
func rewardBasedVideoAdDidClose(_ rewardBasedVideoAd: GADRewardBasedVideoAd)
{
print("Reward based video ad is closed.")
}
For those of you who is facing the the same issue:
You can create a new class for your rootViewController (TabBarController or NavigationController etc.) and implement there something like that:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
dismissalCounter += 1
if (dismissalCounter < 2) {
super.dismiss(animated: flag, completion: completion)
}
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
dismissalCounter = 0
}
override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
dismissalCounter = 0
super.present(viewControllerToPresent, animated: flag, completion: completion)
}
var dismissalCounter : Int = 0
Important! Use this functions inside TabBarController or NavigationController, otherwise it is not gonna work
UPD:
In my case unfortunatly it breaks all NavigationControllers inside a TabBarController (titles don't show and there are no buttons inside them), if I will figure fix actions, I'll let you know
UPD2:
Pretty obvious decision will be to change the initialViewController and view add from it, it'll not be dismissed
UPD3:
I solved this very and very strange:
class ViewController : UIViewController {
override func viewWillAppear(_ animated: Bool) {
if GADRewardBasedVideoAd.sharedInstance().isReady == false {
let request = GADRequest()
rewardBasedVideo!.load(request, withAdUnitID: "ca-app-pub-3940256099942544/1712485313")
}
}
var rewardBasedVideo: GADRewardBasedVideoAd?
#IBAction func ad_button_click(_ sender: Any) {
if rewardBasedVideo!.isReady == true {
let bl = blur()
self.present(bl, animated: true, completion: {
self.rewardBasedVideo?.present(fromRootViewController: bl)
})
}
}
}
class blur : UIViewController {
override func viewDidLoad() {
checkForKeyWindow()
}
func checkForKeyWindow() {
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
if (UIApplication.topViewController() == self) {
print("dismissed and forgotten")
self.dismiss(animated: true, completion: nil)
} else {
print("not keywindow")
self.checkForKeyWindow()
}
})
}
#objc func close() {
self.dismiss(animated: true, completion: nil)
}
}
extension UIApplication {
class func topViewController(base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let nav = base as? UINavigationController {
return topViewController(base: nav.visibleViewController)
}
if let tab = base as? UITabBarController {
let moreNavigationController = tab.moreNavigationController
if let top = moreNavigationController.topViewController, top.view.window != nil {
return topViewController(base: top)
} else if let selected = tab.selectedViewController {
return topViewController(base: selected)
}
}
if let presented = base?.presentedViewController {
return topViewController(base: presented)
}
return base
}
}

How can I navigate from custom class to UIViewController in Swift 4

I have a ViewController which have a button, it calls some method in MyClass.swift. I'm trying to navigate from MyClass.swift to UIViewController MainViewController when I press that button. I implemented this method and I get "navigating..." in the log but nothing happen.
class Myclass {
// some code ...
func someFunc() {
// some code ...
navigateToMainViewController()
}
func navigateToMainViewController() {
let storyboard: UIStoryboard? = UIApplication.shared.keyWindow?.rootViewController?.storyboard
if let myMVC = storyboard?.instantiateViewController(withIdentifier: "MainViewController") {
print("navigating....")
let navController = UIApplication.shared.keyWindow?.rootViewController as? UINavigationController
navController?.pushViewController(myMVC, animated: true)
}else {
print("Something wrong..")
}
}
// some code ...
}
Thank your for your help.
Change your navigation Function and add a parameter of viewController to it, and take a variable in myClass of type UIViewController:
var viewController: UIViewController!
func someFunc(_ viewController: UIViewController) {
self.viewController = viewController
self.navigateToMainViewController()
}
func navigateToMainViewController() {
let storyboard: UIStoryboard? = UIApplication.shared.keyWindow?.rootViewController?.storyboard
if let myMVC = storyboard?.instantiateViewController(withIdentifier: "MainViewController") {
print("navigating....")
self.viewController.navigationController?.pushViewController(myMVC, animated: true)
}else {
print("Something wrong..")
}
}
Then From viewController, Call someFunc() with instance of ViewController:
class ViewController: UIViewController {
#IBAction func buttonPressed(_ sender: UIButton) {
myClassObject.someFunc(self)
}
}

Can we handle the error "Cannot convert the value of type BOOL to expected argument UIiew"

I am tired of trying to PopOver the view controller and searched every where, tried myself also.This issue has again arrived and i am confused what to do next
func showPopover(base: UIView)
{
let storyboard : UIStoryboard = UIStoryboard(name: "Messaging", bundle: nil)
if let viewController = storyboard.instantiateViewControllerWithIdentifier("PreferencesViewController") as?PreferencesViewController
{
let navController = UINavigationController(rootViewController: viewController)
navController.modalPresentationStyle = .Popover
if let pctrl = navController.popoverPresentationController
{
pctrl.delegate = self
pctrl.sourceView = base
pctrl.sourceRect = base.bounds
self.presentViewController(navController, animated: true, completion: nil)
}
}
}
I am calling this method in any one of the actions clicked from UIBarButtons
func optionChoosed(hello:Bool)
{
if (hello)
{
self.showPopover(hello)
}
}
it says Cannot convert the value of type BOOL to expected argument UIiew.. can we fix this or am i going wrong direction.
class SHNewStylesViewController: UIViewController, UIPopoverPresentationControllerDelegate {
var popover: UIPopoverPresentationController? = nil
//MARK: - View life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK: - IBActions
#IBAction func showPopover(sender: AnyObject) {
let genderViewController = storyboard!.instantiateViewControllerWithIdentifier("ViewControllerTwoIdentifier") as! ViewControllerTwo
genderViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
genderViewController.preferredContentSize = CGSize(width: 200.0, height: 400.0) // To change the popover size
popover = genderViewController.popoverPresentationController!
popover!.barButtonItem = sender as? UIBarButtonItem
popover!.delegate = self
presentViewController(genderViewController, animated: true, completion:nil)
}
//MARK: - Popover Presentation Controller Delegate methods
func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
return UIModalPresentationStyle.None
}
}
In my case showPopover is a IBAction of my bar button item. You can you that code inside the showPopover method wherever you want.
Thanks:)

Resources