CosmicMind/Material

Views added using addsubviews are not working inside SnackbarController

ahsanaasim opened this issue · 5 comments

I am trying to use Snackbar in my app. I have tabBarController containing my viewControllers.
I have initiated the Snackbar Setup in the following way.

let homeNavigationController = UINavigationController()
        homeNavigationController.navigationBar.titleTextAttributes = textAttributes
        homeNavigationController.navigationBar.tintColor = Colors.wiseMagenta
        
        let dashboardController = HomeContainerController()
        homeNavigationController.viewControllers = [dashboardController]
        
        let homeSnackBarController = AppSnackbarController(rootViewController: homeNavigationController)
        homeSnackBarController.shouldExtend = false
        homeSnackBarController.tabBarItem = UITabBarItem(title: "Home".localized(), image: UIImage(named: "home"), tag: 0);

When I add homeNavigationController as my tabBarController viewcontroller item, Everything loads perfectly. This is how it looks when I add homeNavigationController directly

Expected Output

I have a UIPageViewController added inside the HomeContainerController which is not getting added when I use the AppSnackbarController as tabBarController viewController. But nothing is getting added as expected. This is how it looks when I use AppSnackbarController

Output I am getting

So there must be something wrong with AppSnackbarController or I am implementing this incorrectly.

My AppSnackbarController code:

import UIKit
import Material

class AppSnackbarController: SnackbarController {
    var shouldExtend = false
    
    open override func prepare() {
        super.prepare()
        delegate = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if shouldExtend {
            extendViews()
        }
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    }
    
    func extendViews() {
        self.tabBarController?.tabBar.isHidden = true
        self.edgesForExtendedLayout = UIRectEdge.bottom
        self.extendedLayoutIncludesOpaqueBars = true
    }
}

extension AppSnackbarController: SnackbarControllerDelegate {
    func snackbarController(snackbarController: SnackbarController, willShow snackbar: Snackbar) {
        print("snackbarController will show")
    }
    
    func snackbarController(snackbarController: SnackbarController, willHide snackbar: Snackbar) {
        print("snackbarController will hide")
    }
    
    func snackbarController(snackbarController: SnackbarController, didShow snackbar: Snackbar) {
        print("snackbarController did show")
    }
    
    func snackbarController(snackbarController: SnackbarController, didHide snackbar: Snackbar) {
        print("snackbarController did hide")
    }
}

My HomeContainerController code

import UIKit
import Material

class HomeContainerController: UIViewController {

    @IBOutlet weak var topContainer: UIView!
    @IBOutlet weak var pagerContainer: UIView!
    
    let subTitleView: UILabel = {
        let leftLabel = UILabel(frame: .zero)
        leftLabel.font = UIFont.appSemiBoldFontWith(size: 14)
        leftLabel.numberOfLines = 1
        leftLabel.translatesAutoresizingMaskIntoConstraints = false
        leftLabel.numberOfLines = 1
        leftLabel.textAlignment = .center
        leftLabel.textColor = Colors.secondaryText!
        return leftLabel
    }()
    
    
    let tabBar = TabBar()
    var buttons = [TabItem]()
    @IBOutlet weak var topView: UIView!
    @IBOutlet weak var anotherview: UIView!
    
//    var topview: UIView!
//    var v: UIView = UIView()
    let homePagerController = HomeControllers(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        initTopPanel()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        initDate()
        initNavBar()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        self.navigationController?.setNavigationBarHidden(false, animated: true)
    }
    
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
    }
    
    
    func initTopPanel() {
        DispatchQueue.main.async {
            self.prepareTopViews()
            self.preparTabViews()
        }
        
        self.homePagerController.tabBar = self.tabBar
        self.addChildViewController(self.homePagerController)
        self.homePagerController.view.translatesAutoresizingMaskIntoConstraints = false
        self.pagerContainer.addSubview(self.homePagerController.view)
        self.pagerContainer.backgroundColor = .red
        NSLayoutConstraint.activate([
            self.homePagerController.view.leadingAnchor.constraint(equalTo: self.pagerContainer.leadingAnchor),
            self.homePagerController.view.trailingAnchor.constraint(equalTo: self.pagerContainer.trailingAnchor),
            self.homePagerController.view.topAnchor.constraint(equalTo: self.pagerContainer.topAnchor),
            self.homePagerController.view.bottomAnchor.constraint(equalTo: self.pagerContainer.bottomAnchor)
            ])
        
        self.homePagerController.didMove(toParentViewController: self)
        
        //        Translator().defaultTranslation()
        for recognizer in self.homePagerController.gestureRecognizers {
            if recognizer is UITapGestureRecognizer {
                recognizer.isEnabled = false
            }
        }
    }
    
    func initNavBar() {
        self.navigationController?.setNavigationBarHidden(true, animated: false)
        if App.shouldToggleNightMode {
            self.toggleNavBarNightMode()
        }
    }
    
    func initDate() {
        let adjustment = UserDefaults.standard.integer(forKey: UserDefaultKeys.IslamicCalenderAdjstment)
        var date = Date()
        date = Calendar.current.date(byAdding: .day, value: adjustment, to: date)!
        subTitleView.text = Utils.shared.arabicDateInFormattedString(format: "d MMMM || yyyy", date: date)
    }
    
    func prepareTopViews() {
        let titleView: UILabel = {
            let leftLabel = UILabel(frame: .zero)
            leftLabel.font = UIFont.appBoldFontWith(size: 19)
            leftLabel.numberOfLines = 1
            leftLabel.translatesAutoresizingMaskIntoConstraints = false
            leftLabel.numberOfLines = 1
            leftLabel.textAlignment = .center
            leftLabel.textColor = Colors.wiseMagenta!
            return leftLabel
        }()
        
        titleView.text = "Quran Touch"
        
        let containerView = UIStackView()
        containerView.axis = .vertical
        containerView.distribution = .fillProportionally
        containerView.alignment = .center
        
        containerView.addArrangedSubview(titleView)
        containerView.addArrangedSubview(subTitleView)
        containerView.backgroundColor = .red
        
        self.topView.addSubview(containerView)
        
        containerView.translatesAutoresizingMaskIntoConstraints = false
        let leftConstraint = containerView.leftAnchor.constraint(equalTo: topView.leftAnchor)
        let rightConstraint = containerView.rightAnchor.constraint(equalTo: topView.rightAnchor)
        let horizontalConstraint = containerView.centerXAnchor.constraint(equalTo: topView.centerXAnchor)
        let verticalConstraint = containerView.centerYAnchor.constraint(equalTo: topView.centerYAnchor)
        NSLayoutConstraint.activate([leftConstraint, rightConstraint, horizontalConstraint, verticalConstraint])
        
        initBarButtons()
    }
    
    func initBarButtons() {
        let profileButton = CircularButton()
        profileButton.setImage(UIImage(named: "dash.settings")!.tint(with: Colors.wiseMagenta!) , for: .normal)
        
        profileButton.addTarget(self, action: #selector(openSettings(sender:)), for: .touchUpInside)
        topView.addSubview(profileButton)
        
        profileButton.translatesAutoresizingMaskIntoConstraints = false
        let heightConstraint = profileButton.heightAnchor.constraint(equalToConstant: 40)
        let widthConstraint = profileButton.widthAnchor.constraint(equalToConstant: 40)
        let rightConstraint = profileButton.rightAnchor.constraint(equalTo: topView.rightAnchor, constant: -16.0)
        let verticalConstraint = profileButton.centerYAnchor.constraint(equalTo: topView.centerYAnchor)
        NSLayoutConstraint.activate([heightConstraint, widthConstraint, rightConstraint, verticalConstraint])
        
        let freePremiumButton = UIButton()
        freePremiumButton.setImage(UIImage(named: "home_free_premium")! , for: .normal)
        topView.addSubview(freePremiumButton)
        
        freePremiumButton.translatesAutoresizingMaskIntoConstraints = false
        let heightConstraint2 = freePremiumButton.heightAnchor.constraint(equalToConstant: 30)
        let widthConstraint2 = freePremiumButton.widthAnchor.constraint(equalToConstant: 30)
        let rightConstraint2 = freePremiumButton.leftAnchor.constraint(equalTo: topView.leftAnchor, constant: 16.0)
        let verticalConstraint2 = freePremiumButton.centerYAnchor.constraint(equalTo: topView.centerYAnchor)
        NSLayoutConstraint.activate([heightConstraint2, widthConstraint2, rightConstraint2, verticalConstraint2])
        
    }
    
    func preparTabViews() {
        self.prepareButtons()
        self.prepareTabBar()
    }
    
    @objc func openSettings(sender: Any) {
        let vc = ProfileController()
        self.navigationController?.pushViewController(vc, animated: true)
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destination.
        // Pass the selected object to the new view controller.
    }
    */

}


extension HomeContainerController {
    fileprivate func prepareButtons() {
        let btn1 = TabItem(title: "Dua", titleColor: Colors.wiseMagenta!)
        btn1.pulseAnimation = .centerRadialBeyondBounds
        btn1.tag = 0
        let attributes = [
            NSAttributedStringKey.font: UIFont.appRegularFontWith(size: 15),
            NSAttributedStringKey.foregroundColor: Colors.secondaryText!
        ]
        
        let selectedAttributes = [
            NSAttributedStringKey.font: UIFont.appSemiBoldFontWith(size: 15),
            NSAttributedStringKey.foregroundColor: Colors.wiseMagenta!
        ]
        
        btn1.setAttributedTitle(NSAttributedString(string: "Dashboard", attributes: attributes), for: .normal)
        btn1.setAttributedTitle(NSAttributedString(string: "Dashboard", attributes: selectedAttributes), for: .selected)
        buttons.append(btn1)
        
        let btn2 = TabItem(title: "Community", titleColor: Colors.wiseMagenta!)
        btn2.tag = 1
        btn2.setAttributedTitle(NSAttributedString(string: "Explore", attributes: attributes), for: .normal)
        btn2.setAttributedTitle(NSAttributedString(string: "Explore", attributes: selectedAttributes), for: .selected)
        btn2.pulseAnimation = .none
        
        buttons.append(btn2)
    }
    
    fileprivate func prepareTabBar() {
        
//        tabBar.delegate = self
        
        tabBar.dividerColor = Color.clear
        
        
        tabBar.lineColor = Colors.wiseMagenta!
        tabBar.lineAlignment = .bottom
        
        tabBar.backgroundColor = Color.clear
        tabBar.tabItems = buttons
        
        tabBar.tabBarLineStyle = .custom { tabItem in
            if tabItem.tag == 1 {
                return tabItem.bounds.width - 30
            }
            return tabItem.bounds.width
        }
        tabBar.lineHeight = 1
        tabBar.tabBarStyle = .nonScrollable
        tabBar.tabBarCenteringStyle = .never
        tabBar.tabItemsInterimSpace = 10
        
        //        tabBar.tabBarLineStyle = .auto
        tabBar.frame.size.width = 180
        tabBar.frame.size.height = 30
        
        anotherview.addSubview(tabBar)
        
        tabBar.translatesAutoresizingMaskIntoConstraints = false
        let horizontalConstraint = tabBar.centerXAnchor.constraint(equalTo: anotherview.centerXAnchor, constant: 5.0)
        let verticalConstraint = tabBar.centerYAnchor.constraint(equalTo: anotherview.centerYAnchor)
        NSLayoutConstraint.activate([horizontalConstraint, verticalConstraint])
    }
}

Interestingly, when I came from background, everything gets added as expected when using AppSnackBarController.

Which controller is the parent of homeSnackBarController?


PRO TIP:
This:

self.topView.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
let leftConstraint = containerView.leftAnchor.constraint(equalTo: topView.leftAnchor)
let rightConstraint = containerView.rightAnchor.constraint(equalTo: topView.rightAnchor)
let horizontalConstraint = containerView.centerXAnchor.constraint(equalTo: topView.centerXAnchor)
let verticalConstraint = containerView.centerYAnchor.constraint(equalTo: topView.centerYAnchor)
NSLayoutConstraint.activate([leftConstraint, rightConstraint, horizontalConstraint, verticalConstraint])

Can be replaced by:

topView.layout(containerView)
  .leftRight() /// same as .left().right()
  .center() /// same as .centerX().centerY()

Learn more at #1185

Thanks for the PRO TIP.

This is how I added homeSnackBarController inside my Tabbar.

let tabBarController = Tabber()
        // Do any additional setup after loading the view, typically from a nib.
        
        tabBarController.viewControllers = [homeSnackBarController, quranSnackBarController, prayerNavigationController, duaSnackBarController]

Tabber Class:

import UIKit

@objc class Tabber: UITabBarController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        delegate = self
    }
    
    @objc func set(selectedIndex index : Int) {
        _ = self.tabBarController(self, shouldSelect: self.viewControllers![index])
    }
}

extension Tabber: UITabBarControllerDelegate  {
    func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
        
        guard let fromView = selectedViewController?.view, let toView = viewController.view else {
            return false // Make sure you want this as false
        }
        
        if fromView != toView {
            UIView.transition(from: fromView, to: toView, duration: 0.1, options: [.transitionCrossDissolve], completion: nil)
        }
        
        return true
    }
}

@ahsanaasim @OrkhanAlikhanov is this still an issue?

I solved using another navigation controller above appSnackbar which i think is a bad solution..Cuz in that case I have to use two navigationController.