Reputation: 1601
At the moment I have a standard tab bar, when tapped goes to its corresponding viewController. But I want to make a menu pop out from tab bar when more tab is selected, as shown in below image.
Is any suggestion to implement this? Thanks in advance.
Upvotes: 16
Views: 905
Reputation: 4849
1) Create a "Tab5ViewController" and use this:
static func takeScreenshot(bottomPadding padding: CGFloat = 0) -> UIImage? {
let layer = UIApplication.shared.keyWindow!.layer
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(CGSize(width: layer.frame.size.width, height: layer.frame.size.height - padding), false, scale)
guard let context = UIGraphicsGetCurrentContext() else { return nil }
layer.render(in: context)
let screenshot = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return screenshot
}
Use the screenshot as a background image for your "Tab5ViewController"
2) In your "Tab5ViewController" you can have the stack component (the additional tabs) and then just add/remove child view controllers based on the selection
3) fix edge cases (like tab selection highlight and so on...)
Upvotes: 0
Reputation: 6555
As per my understanding what you want is that, tab 1 is selected and user goes to tab 5 then background will be tab 1 & vice-versa for tab 2,3 & 4 and there should be pop up like buttons as shown in your image. please correct me if I'm wrong.
For this you have to capture the image while user navigate through tabs.
Please find below code in AppDelegate,
var currentImage: UIImage! //It will be public variable
Tabbar delegate methods,
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
if tabBarController.selectedIndex == 4 {
let moreVC = tabBarController.selectedViewController as! MoreVC
moreVC.currentImage = currentImage
}
}
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if tabBarController.selectedIndex != 4 {
let navController = tabBarController.selectedViewController as! UINavigationController
let viewController = navController.viewControllers.last
currentImage = Common.imageWithView(inView: (viewController?.navigationController?.view)!) //UIImage(view: (viewController?.navigationController?.view)!)
}
return true
}
Here I've taken static 4 as last tab index & MoreVC will be the associated ViewController of tab index 4.
Common class to get image from view,
class Common {
static func imageWithView(inView: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(inView.bounds.size, inView.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
inView.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
}
Please find MoreVC,
@IBOutlet weak var imageView: UIImageView!
var currentImage: UIImage! {
didSet {
imageView.image = currentImage
}
}
Please find below image for MoreVC Storyboard. Look it does not contain NavigationController like all other ViewControllers.
Let me know in case of any queries.
Upvotes: 0
Reputation: 2905
This is an abuse of the UI patterns layout in Apples HIG. Specifically:
Use a tab bar strictly for navigation. Tab bar buttons should not be used to perform actions. If you need to provide controls that act on elements in the current view, use a toolbar instead.
This control should be used to flatten your app hierarchy. It seems that in this case you are mixing functionality of the button. Sometimes it selects a separate view controller, sometimes it displays a action list. This is a confusing situation for users and should be avoided.
A way you could achieve this and still adhere to HIG is by using navigation or tool bars. Imbed this control in a toolbar button. The most simple case would be to invoke a UIActionController
with the .actionSheet
style selected.
Upvotes: 0
Reputation: 71
Instead of showing a menu, you could use a scrollable tabs view for a better UI. If you prefer using a library, here's a simple scrollable tab-bar you could implement.
Upvotes: 0
Reputation: 424
I would recommend you do so:
First, you should think of all the tab types that could be in tab bar. On your screenshot there are tabs, that present controller, and tab, that presents menu. So we could create enum with all these types:
enum TabType {
case controller
case menu
}
After that you can store array of tab types in order they are shown in tab bar, for your screenshot like so
let tabTypes: [TabType] = [.controller, .controller, .controller, .controller, .menu]
Then you should implement UITabBarControllerDelegate
's func tabBarController(_:, shouldSelect:) -> Bool
method, which returns true
if tab bar is allowed to select the passed controller, and false
otherwise.
If you return true
than all other work (like presenting view controller and other stuff) tab bar controller will do for you.
In your case you want to execute custom action on tab click, so you should return false
. Before returning you should present your menu.
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if let index = tabBarController.viewControllers?.index(of: viewController),
index < tabBarTypes.count {
let type = tabBarTypes[index]
switch type {
case .menu:
// perform your menu presenting here
return false
case .controller:
// do nothing, just return true, tab bar will do all work for you
return true
}
}
return true
}
In this implementation you can easily change tab types order or add some another tab type and handle it appropriate.
Upvotes: 4
Reputation: 361
Its not good UI but although if you want.
First You have to implement delegate method of UITabbarControllerDelegate as below
func tabBarController(_ tabBarController: UITabBarController, shouldSelect
viewController: UIViewController) -> Bool {
if viewController.classForCoder == moreViewController.self
{
let popvc = MoreSubMenuViews(nibName: "MoreSubMenuViews", bundle: Bundle.main)
self.addChildViewController(popvc)
let tabbarHeight = tabBar.frame.height
let estimatedWidth:CGFloat = 200.0
let estimatedHeight:CGFloat = 300.0
popvc.view.frame = CGRect(x:self.view.frame.width - estimatedWidth, y: self.view.frame.height - estimatedHeight - tabbarHeight, width: estimatedWidth, height: estimatedHeight)
self.view.addSubview(popvc.view)
popvc.didMove(toParentViewController: self)
print("sorry stop here")
return true // if you want not to select return false here
}else{
//remove popup logic here if opened
return true
}
}
Here moreViewController is last tab controller & MoreSubMenuViews is nib/xib file which contains buttons shown in you image.
Upvotes: 0