Custom UITabBarController - DidSelect/AnyCustomization delegate problem - ios

I created custom TabBar class, but I have few problems, how I can call any function from this class when for example tab is hidden? (I would like to hide my stripe when tab bar is hidden) Also when I use tabBarController?.selectedIndex = 3 the delegate didSelect is not called, how can I solve it? That is my simple code. Thanks for any help
class customTabBar: UITabBarController {
var stripe = UIView()
override func viewDidLoad() {
super.viewDidLoad()
let cellWidth = tabBar.frame.width/5
stripe = UIView(frame: CGRect(x: 0, y: tabBar.frame.minY + 20, width: (tabBar.frame.width/5) * 0.6, height: 6))
stripe.center.x = cellWidth/2
stripe.applyGradient(colours: [UIColor.init(hexFromString: "5897ee"),UIColor.init(hexFromString: "5228d8")])
stripe.layer.cornerRadius = 2
stripe.layer.masksToBounds = true
self.view.addSubview(stripe)
}
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
let index: Int = item.tag + 1
let cellWidth = tabBar.frame.width/5
let newPostion = cellWidth * CGFloat(index)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 0.3, options: .curveEaseInOut, animations: {
self.stripe.center.x = newPostion - (cellWidth/2)
})
}
}

class MyTabBarController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
//Add the stripe to tabBar,so it will hidden when tabBar hidden
let cellWidth = tabBar.frame.width/5
let stripe = UIView(frame: CGRect(x: 0, y: tabBar.frame.minY + 20, width: (tabBar.frame.width/5) * 0.6, height: 6))
stripe.center.x = cellWidth/2
stripe.layer.cornerRadius = 2
stripe.layer.masksToBounds = true
self.tabBar.addSubview(stripe)
}
//use this to observe tabBarController?.selectedIndex = 3
override var selectedIndex: Int{
didSet{
//do what you want
}
}
}
extension UIViewController {
//use this to call get MyTabBarController instance and call any function
var myTabBarcontroller : MyTabBarController?{
get{
return self.tabBarController as? MyTabBarController
}
}
}

Related

ViewController's properties are nil

I want to make SideMenu.
my code of HomeViewController:
lazy var sideMenu: SideMenuViewController = {
let menu = SideMenuViewController()
menu.stayViewObj = self
return menu
}()
Menu button's Action:
#objc func handleMenuBtn () {
sideMenu.openMenu()
}
SideMenu's viewDidLoad :
override func viewDidLoad(){
constraintLeadingPropertiesView.constant = -viewSelectProperties.frame.width
}
SideMenu's openMenu method:
func openMenu() {
debugPrint(">>>>openMenu")
let statusBarHeight = UIApplication.shared.statusBarFrame.height
let yCoordinate: CGFloat = statusBarHeight + 44.0
guard let window = UIApplication.shared.keyWindow else { return }
view.backgroundColor = UIColor(white: 0, alpha: 0.5)
view.alpha = 0
view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(closeMenu)))
view.frame = window.frame
startFrame = CGRect(x: 0, y: yCoordinate, width: 0, height: window.frame.height - yCoordinate)
view.frame = startFrame!
window.addSubview(view)
UIView.animate(withDuration: 0.7, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.view.alpha = 1
self.view.frame = CGRect(x: 0, y: yCoordinate, width: window.frame.width - 80, height: window.frame.height - yCoordinate)
}, completion: nil)
}
Now, I am getting constraintLeadingPropertiesView=nil and all other properties of SideMenuController are also nil accepting stayViewObj.
so get crash on viewDidLoad.
how to solve this... any suggestion also helpful for me..
Thanks!
need to instantiateInitialViewController instead of create object via lazy Var.
let menu = UIStoryboard.init(name: "Main", bundle: nil).instantiateInitialViewController() as? SideMenuViewController

Swift 4 Viewcontroller dependency Injection in Class

I'm learning swift and trying to figure out how to add a view controller as a dependency into my Class I'm creating. Ideally I'd like to add it in the init stage so it's 'dependable'
But I can't quite figure it out - so I'm hoping someone can help me along the way. The error I'm getting is: Property 'self.homeController' not initialized at super.init call
Basically I have a Class that creates an overlay with a pop-up on it that has a UICollectionView that is clickable. When the you click the item, the menu animates out and THEN on complete fires the function from the homecontroller.
class SettingLauncher: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let homeController: HomeController
func showSettings(){
// window is the full device since the view is smaller due to nav
if let window = UIApplication.shared.keyWindow {
blackView.alpha = 0
blackView.backgroundColor = UIColor(white: 0, alpha: 0.6)
blackView.frame = window.frame // set RECT to the same size as device
blackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleDismiss)))
window.addSubview(blackView)
window.addSubview(collectionView)
let height:CGFloat = CGFloat(settings.count) * cellHeight
let y = window.frame.height - height
collectionView.frame = CGRect(x: 0, y: window.frame.height, width: window.frame.width, height: window.frame.height / 2)
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.blackView.alpha = 1
self.collectionView.frame = CGRect(x: 0, y: y, width: window.frame.width, height: window.frame.height / 2)
}, completion: nil)
}
}
#objc func handleDismiss(){
UIView.animate(withDuration: 0.5,
animations:{
self.blackView.alpha = 0
if let window = UIApplication.shared.keyWindow {
self.collectionView.frame = CGRect(x: 0, y: window.frame.height, width: window.frame.width, height: window.frame.height / 2)
}
}, completion: {_ in
self.blackView.removeFromSuperview()
self.homeController.showSettingsController()
})
}
override init(){
super.init()
self.homeController = HomeController()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(SettingsCell.self, forCellWithReuseIdentifier: cellID)
}
}
In the homecontroller, The menu button that you click initializes the settingsController and tells it to display:
let settingsLauncher = SettingLauncher()
#objc func handleMore(){
settingsLauncher.showSettings()
}
func showSettingsController(){
let dummyController = UIViewController()
navigationController?.pushViewController(dummyController, animated: true)
}
The error is telling you that you must have initialised the homeController property before you call super.init() which you don't do.
Change the code to this:
override init(){
self.homeController = HomeController()
super.init()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(SettingsCell.self, forCellWithReuseIdentifier: cellID)
}
Figured it out with some help from #UpholderOfTruth and #Tj3n. Posting the working code below.
class SettingLauncher: NSObject, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let homeController: HomeController
...other UICollectionview functions
// on Item click insdie UIViewCollection
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
UIView.animate(withDuration: 0.5,
animations:{
self.blackView.alpha = 0
if let window = UIApplication.shared.keyWindow {
self.collectionView.frame = CGRect(x: 0, y: window.frame.height, width: window.frame.width, height: window.frame.height / 2)
}
}, completion: {_ in
let setting = self.settings[indexPath.item]
self.blackView.removeFromSuperview()
// Call function from Injected ViewController
self.homeController.showControllerSetting(setting: setting)
})
}
init(controller: HomeController){
homeController = controller
super.init()
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(SettingsCell.self, forCellWithReuseIdentifier: cellID)
}
}
Functions in my HomeController initializing the SettingsLauncher class
lazy var settingsLauncher:SettingLauncher = {
let launcher = SettingLauncher(controller: self)
return launcher
}()
#objc func handleMore(){
settingsLauncher.showSettings()
}
func showControllerSetting(setting: Setting){
let dummyController = UIViewController()
navigationController?.pushViewController(dummyController, animated: true)
}

UITabBar personalization, color and separator lines

I'm making this iOS app (Swift 3) that has a tab bar and I don't find a way to personalized it to the way I want to. I want to add lines in between each icon and I want it to be red when selected, like this:
Custom a class inherited from UITabBarController, and then use it as your TabBarController's class. The main procedure provided here:
import UIKit
class MainTabBarController: UITabBarController,UITabBarControllerDelegate {
var firstBackgroundView:UIView!
//var secondBackgroundView:UIView!
//......
override func viewDidLoad() {
super.viewDidLoad()
//Lines:
let topline = CALayer()
topline.frame = CGRect(x: 0, y: 0, width: self.tabBar.frame.width, height: 2)
topline.backgroundColor = UIColor.gray.cgColor
self.tabBar.layer.addSublayer(topline)
let firstVerticalLine = CALayer()
firstVerticalLine.frame = CGRect(x: self.tabBar.frame.width / 5, y: 0, width: 2, height: self.tabBar.frame.height)
firstVerticalLine.backgroundColor = UIColor.gray.cgColor
self.tabBar.layer.addSublayer(firstVerticalLine)
//Continue to add other lines to divide tab items...
//......
//Background views
firstBackgroundView = UIView(frame: CGRect(x: 0, y: 0, width: self.tabBar.frame.width / 5, height: self.tabBar.frame.height))
firstBackgroundView.backgroundColor = UIColor.red
firstBackgroundView.isHidden = false //true for others.
self.tabBar.addSubview(firstBackgroundView)
self.tabBar.sendSubview(toBack: firstBackgroundView)
//Continue to add other background views for each tab item...
//......
self.delegate = self
}
public func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if self.selectedIndex == 0 {
firstBackgroundView.isHidden = false
//othersBackgroundView.isHidden = true
}
else if self.selectedIndex == 1 {
//......
}
}
}

Subview to TabBarController is blocking tab bar items in iOS

I'm working on something like the draggable video player in youtube app. I've been able to make the swipe down work and I'm adding the video player view as a subview to the Tab bar controller which is the root view of my application. The issue is when I swipe down to minimise the video, I'm not able to select two tab bar items underneath the video player. How do I solve this?
In the image, the Live and Me tabs are not selectable unless I remove the video player from the screen.
My view hierarchy is UITabBarController > UINavigationController > UIViewController so i subclassed UINavigationController:
class CFNavigationController: UINavigationController, CFVideoPlayerControllerDelegate {
//MARK: Properties
lazy var videoPlayerViewController: CFVideoPlayerController = {
let pvc: CFVideoPlayerController = self.storyboard?.instantiateViewController(withIdentifier: "videoPlayer") as! CFVideoPlayerController
pvc.view.frame = CGRect.init(origin: self.hiddenOrigin, size: UIScreen.main.bounds.size)
pvc.delegate = self
return pvc
}()
let statusView: UIView = {
let st = UIView.init(frame: UIApplication.shared.statusBarFrame)
st.backgroundColor = UIColor.white
st.alpha = 0.15 // 0.15
return st
}()
let hiddenOrigin: CGPoint = {
let y = UIScreen.main.bounds.height - (UIScreen.main.bounds.width * 9 / 32) - 10
let x = -UIScreen.main.bounds.width
let coordinate = CGPoint.init(x: x, y: y)
return coordinate
}()
let minimizedOrigin: CGPoint = {
let x = UIScreen.main.bounds.width/2 - 10
let y = UIScreen.main.bounds.height - (UIScreen.main.bounds.width * 9 / 32) - 60
let coordinate = CGPoint.init(x: x, y: y)
return coordinate
}()
let fullScreenOrigin = CGPoint.init(x: 0, y: 0)
//Methods
func animatePlayView(toState: stateOfVC) {
switch toState {
case .fullScreen:
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 5, options: UIViewAnimationOptions.beginFromCurrentState, animations: {
self.videoPlayerViewController.view.frame.origin = self.fullScreenOrigin
})
case .minimized:
UIView.animate(withDuration: 0.3, animations: {
self.videoPlayerViewController.view.frame.origin = self.minimizedOrigin
})
case .hidden:
UIView.animate(withDuration: 0.3, animations: {
self.videoPlayerViewController.view.frame.origin = self.hiddenOrigin
self.videoPlayerViewController.videoPlayerView.player?.replaceCurrentItem(with: nil)
})
}
}
func positionDuringSwipe(scaleFactor: CGFloat) -> CGPoint {
let width = UIScreen.main.bounds.width * 0.5 * scaleFactor
let height = width * 9 / 16
let x = (UIScreen.main.bounds.width - 10) * scaleFactor - width
let y = (UIScreen.main.bounds.height - 10 ) * scaleFactor - height
let coordinate = CGPoint.init(x: x, y: y)
return coordinate
}
//MARK: Delegate methods
func didMinimize() {
self.animatePlayView(toState: .minimized)
}
func didMaximize(){
self.animatePlayView(toState: .fullScreen)
}
func didEndedSwipe(toState: stateOfVC){
self.animatePlayView(toState: toState)
}
func swipeToMinimize(translation: CGFloat, toState: stateOfVC){
switch toState {
case .fullScreen:
self.videoPlayerViewController.view.frame.origin = self.positionDuringSwipe(scaleFactor: translation)
case .hidden:
// self.videoPlayerViewController.view.frame.origin.x = UIScreen.main.bounds.width/2 - abs(translation) - 10
self.videoPlayerViewController.removeFromParentViewController()
case .minimized:
self.videoPlayerViewController.view.frame.origin = self.positionDuringSwipe(scaleFactor: translation)
}
}
//MARK: ViewController lifecycle
override func viewDidLoad() {
super.viewDidLoad()
self.tabBarController?.view.addSubview(self.videoPlayerViewController.view)
self.tabBarController?.view.bringSubview(toFront: self.videoPlayerViewController.view)
}
override func viewDidAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
// Give View Controllers the power of their own rotation
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return visibleViewController?.supportedInterfaceOrientations ?? super.supportedInterfaceOrientations
}
open override var shouldAutorotate: Bool {
return visibleViewController?.shouldAutorotate ?? super.shouldAutorotate
} }
Here is how I add it to as subview:
self.tabBarController?.view.addSubview(self.videoPlayerViewController.view)
self.tabBarController?.view.bringSubview(toFront: self.videoPlayerViewController.view)

IOS set UIViewController.view.frame = CGCGRect(x: -200..) can not click button

I want put several UIViewController together:
leftViewController.view.frame = CGRect(x: -200, y: 0.0, width: size.width/drawerSize, height: size.height)
// Center Drawer
centerViewController.view.frame = CGRect(x: leftViewController.view.frame.width, y: 0.0, width: centerWidth, height: size.height)
// Right Drawer
rightViewController.view.frame = CGRect(x: centerViewController.view.frame.origin.x + centerViewController.view.frame.size.width, y: 0.0, width: size.width/drawerSize, height: size.height)
In the first line I use
leftViewController.view.frame = CGRect(x: -200, y....)
They will show correctly but I can not click buttons on leftViewController.
If
leftViewController.view.frame = CGRect(x: 0.0, y...)
then could click button but this layout is not I want.
The full code is posted by #Kevin Scardina Slide Sidebar Menu IOS 8 Swift
It now function as the picture below, And I'm trying to modify it like a slide menu bar which could hid left and right menu.
/*
To use simply instantiate NVMDrawerController as your root view in your AppDelegate, or in the
StoryBoard.
Once NVMDrawerController is instantiated, set the drawerSize of the NVMDrawerController,
and its leftViewControllerIdentifier, centerViewControllerIdentifier, and
rightViewControllerIdentifier to the Storyboard Identifier of the UIViewController
you want in the different locations.
*/
class NVMDrawerController: UIViewController {
// This is where you set the drawer size (i.e. for 1/3rd use 3.0, for 1/5 use 5.0)
var drawerSize:CGFloat = 4.0
var leftViewControllerIdentifier:String = "LeftController"
var centerViewControllerIdentifier:String = "CenterController"
var rightViewControllerIdentifier:String = "RightController"
private var _leftViewController:UIViewController?
var leftViewController:UIViewController {
get{
if let vc = _leftViewController {
return vc;
}
return UIViewController();
}
}
private var _centerViewController:UIViewController?
var centerViewController:UIViewController {
get{
if let vc = _centerViewController {
return vc;
}
return UIViewController();
}
}
private var _rightViewController:UIViewController?
var rightViewController:UIViewController {
get{
if let vc = _rightViewController {
return vc;
}
return UIViewController();
}
}
static let NVMDrawerOpenLeft = 0
static let NVMDrawerOpenRight = 1
var openSide:Int {
get{
return _openSide;
}
}
private var _openSide:Int = NVMDrawerOpenLeft
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Instantiate VC's with storyboard ID's
_leftViewController = instantiateViewControllers(leftViewControllerIdentifier)
_centerViewController = instantiateViewControllers(centerViewControllerIdentifier)
_rightViewController = instantiateViewControllers(rightViewControllerIdentifier)
// Call configDrawers() and pass the drawerSize variable.
drawDrawers(UIScreen.mainScreen().bounds.size)
self.view.addSubview(leftViewController.view)
self.view.addSubview(centerViewController.view)
self.view.addSubview(rightViewController.view)
}
override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
coordinator.animateAlongsideTransition({ (UIViewControllerTransitionCoordinatorContext) -> Void in
// This is for beginning of transition
self.drawDrawers(size)
}, completion: { (UIViewControllerTransitionCoordinatorContext) -> Void in
// This is for after transition has completed.
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Drawing View
func drawDrawers(size:CGSize) {
// Calculate Center View's Size
let centerWidth = (size.width/drawerSize) * (drawerSize - 1)
// Left Drawer
leftViewController.view.frame = CGRect(x: 0.0, y: 0.0, width: size.width/drawerSize, height: size.height)
// Center Drawer
centerViewController.view.frame = CGRect(x: leftViewController.view.frame.width, y: 0.0, width: centerWidth, height: size.height)
// Right Drawer
rightViewController.view.frame = CGRect(x: centerViewController.view.frame.origin.x + centerViewController.view.frame.size.width, y: 0.0, width: size.width/drawerSize, height: size.height)
//rightViewController = rc
// Capture the Swipes
let swipeRight = UISwipeGestureRecognizer(target: self, action: Selector("swipeRightAction:"))
swipeRight.direction = .Right
centerViewController.view.addGestureRecognizer(swipeRight)
let swipeLeft = UISwipeGestureRecognizer(target: self, action: Selector("swipeLeftAction:"))
swipeLeft.direction = .Left
centerViewController.view.addGestureRecognizer(swipeLeft)
if(openSide == NVMDrawerController.NVMDrawerOpenLeft){
openLeftDrawer()
}
else{
openRightDrawer()
}
}
// MARK: - Open Drawers
func openLeftDrawer() {
_openSide = NVMDrawerController.NVMDrawerOpenLeft
UIView.animateWithDuration(0.1, delay: 0, options: UIViewAnimationOptions.CurveEaseIn, animations:
{ () -> Void in
// move views here
self.view.frame = CGRect(x: 0.0, y: 0.0, width: self.view.bounds.width, height: self.view.bounds.height)
}, completion:
{ finished in
})
}
func openRightDrawer() {
_openSide = NVMDrawerController.NVMDrawerOpenRight
UIView.animateWithDuration(0.1, delay: 0, options: UIViewAnimationOptions.CurveEaseIn, animations:
{ () -> Void in
// move views here
self.view.frame = CGRect(x: self.view.bounds.origin.x - self.leftViewController.view.bounds.size.width, y: 0.0, width: self.view.bounds.width, height: self.view.bounds.height)
}, completion:
{ finished in
})
}
// MARK: - Swipe Handling
func swipeRightAction(rec: UISwipeGestureRecognizer){
self.openLeftDrawer()
}
func swipeLeftAction(rec:UISwipeGestureRecognizer){
self.openRightDrawer()
}
// MARK: - Helpers
func instantiateViewControllers(storyboardID: String) -> UIViewController {
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("\(storyboardID)") as? UIViewController{
return viewController;
}
return UIViewController();
}
}
When your view is outside of its superview,it can't receive any touch events.You should enumerate subviews in UIView(its superview) touchWithEvents function and make it receive the event.

Resources