programatically add two image to above my label - ios

I'm using a custom library : CAPSPageMenu . Here I have one view controller and I programmatically add the name for that, the view has two tabs. When i click any tab that respective page will display below.
I have set the name and added the animation to swipe between two tabs. But now I need to add image on above of my label, how would I accomplish that?
Here is my code !:
var pageMenu : CAPSPageMenu? // pager object
var controllerArray : [UIViewController] = [] // number view pager
override func viewDidLoad() {
super.viewDidLoad()
pageSettings()
}
func pageSettings() {
tableView.dataSource = self
tableView.delegate = self
let controller1 : UIViewController = UIViewController()
controller1.title = "FAVOURITES"
controllerArray.append(controller1)
let controller2 : UIViewController = UIViewController()
controller2.title = "RECENT SEARCH"
controllerArray.append(controller2)
let leftRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(self.didLeftSwipe(_:)))
leftRecognizer.direction = .Left
self.tableView.addGestureRecognizer(leftRecognizer)
let rightRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(self.didRightSwipe(_:)))
rightRecognizer.direction = .Right
self.tableView.addGestureRecognizer(rightRecognizer)
}
Like this i need to add image.As i mention the box above the two labels

Seems you are used a custom library CAPSPageMenu, unfortunately what do you want to do is not available.
However with swift you can do extraordinary things such as expanding PageMenu directly in your code: (I've maded just an example but you can start from it):
Add this code at the bottom of your class or whatever you want:
extension UIView {
func fadeIn(duration: NSTimeInterval = 1.0, delay: NSTimeInterval = 0.0, completion: ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 1.0
}, completion: completion) }
func fadeOut(duration: NSTimeInterval = 1.0, delay: NSTimeInterval = 0.0, completion: (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animateWithDuration(duration, delay: delay, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 0.0
}, completion: completion)
}
}
extension CAPSPageMenu {
func addImageOverMyMenuItem(index:Int,imageName:String) {
if index>=0 && index<self.menuItems.count || self.menuItems[index].titleLabel!.frame.height>0 {
var labelFrame = self.menuItems[index].titleLabel!.frame
let image: UIImage = UIImage(named: imageName)!
let bgImage = UIImageView(image: image)
labelFrame.origin.y = self.menuItems[index].frame.origin.y
labelFrame.origin.x += (labelFrame.width/10)
labelFrame.size.width -= (labelFrame.width/10)*2
labelFrame.size.height = self.menuItems[index].titleLabel!.frame.size.height/3
bgImage.frame = labelFrame
bgImage.tag = 9999
bgImage.alpha = 0.0
self.menuItems[index].addSubview(bgImage)
bgImage.fadeIn(completion: {
(finished: Bool) -> Void in
if finished {
// image is showed, do whatever you want
}
})
} else {
print("Due to index out of range or titleLabel dont yet setted i cannot set image")
}
}
func removeImageOverMyMenuItem(index:Int) {
if index>=0 && index<self.menuItems.count {
if let bgImage = self.menuItems[index].viewWithTag(9999) {
bgImage.fadeOut(completion: {
(finished: Bool) -> Void in
if finished {
bgImage.removeFromSuperview()
}
})
}
}
}
}
You can easily use to add an image:
pageMenu?.addImageOverMyMenuItem(0, imageName: "search.png")
and to remove :
pageMenu?.removeImageOverMyMenuItem(0)
P.S. The result would be this:
So , finally following the official demo 1 project (PageMenuDemoStoryboard) in the ViewController at the method viewDidAppear i can add my images like this:
// Initialize scroll menu
pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRectMake(0.0, 0.0, self.view.frame.width, self.view.frame.height), pageMenuOptions: parameters)
pageMenu?.addImageOverMyMenuItem(0, imageName: "search.png")
pageMenu?.addImageOverMyMenuItem(1, imageName: "search.png")
pageMenu?.addImageOverMyMenuItem(2, imageName: "search.png")
self.addChildViewController(pageMenu!)
self.view.addSubview(pageMenu!.view)
pageMenu!.didMoveToParentViewController(self)
...
And you obtain this result:
P.S.S. If it's not clear, I've made this example just using an image named "search.png" but you can use all images do you want to insert in your project.

You are using PageMenu, right?
Basically, PageMenu doesn't have the feature satisfy your needs.
If you want to use PageMenu, you have to modify this module.
Check MenuItemView Class in CAPSPageMenu.swift

I have also customised CAPSPageMenu , using the answer of #Alessandro Ornano that helped me to add the image above text, so anyone using can also set width,height of image and also can set the position of image as per device by using code below.Hope it will help someone.
extension UIView {
func fadeIn(duration: TimeInterval = 0.0, delay: TimeInterval = 0.0, completion: #escaping ((Bool) -> Void) = {(finished: Bool) -> Void in}) {
UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = 1.0
}, completion: completion) }
func fadeOut(duration: TimeInterval = 0.0, delay: TimeInterval = 0.0, completion: #escaping (Bool) -> Void = {(finished: Bool) -> Void in}) {
UIView.animate(withDuration: duration, delay: delay, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.alpha = 0.0
}, completion: completion)
}
}
extension CAPSPageMenu {
func addImageOverMyMenuItem(index:Int,imageName:String) {
if index>=0 && index<self.menuItems.count || self.menuItems[index].titleLabel!.frame.height>0 {
var labelFrame = self.menuItems[index].titleLabel!.frame
let image: UIImage = UIImage(named: imageName)!
let bgImage = UIImageView(image: image)
labelFrame.origin.y = self.menuItems[index].frame.origin.y
labelFrame.origin.x += (labelFrame.width/9)
labelFrame.size.width -= (labelFrame.width/10)*5
labelFrame.size.height = self.menuItems[index].titleLabel!.frame.size.height/3
bgImage.frame = labelFrame
bgImage.tag = 9999
bgImage.alpha = 0.0
if UIDevice().userInterfaceIdiom == .phone {
switch UIScreen.main.nativeBounds.height {
case 480:
print("iPhone Classic")
case 960:
print("iPhone 4 or 4S")
bgImage.frame = CGRect(origin: CGPoint(x:20 ,y :0), size: CGSize(width:30, height: 30))
case 1136:
print("iPhone 5 or 5S or 5C")
bgImage.frame = CGRect(origin: CGPoint(x:20 ,y :0), size: CGSize(width:35, height: 35))
case 1334:
print("iPhone 6 or 6S")
bgImage.frame = CGRect(origin: CGPoint(x:30 ,y :0), size: CGSize(width:35, height: 35))
case 2208:
print("iPhone 6+ or 6S+")
bgImage.frame = CGRect(origin: CGPoint(x:35 ,y :0), size: CGSize(width:35, height: 35))
default:
print("unknown")
bgImage.frame = CGRect(origin: CGPoint(x:40 ,y :0), size: CGSize(width:30, height: 30))
}
}
self.menuItems[index].addSubview(bgImage)
bgImage.fadeIn(completion: {
(finished: Bool) -> Void in
if finished {
// image is showed, do whatever you want
}
})
} else {
print("Due to index out of range or titleLabel dont yet setted i cannot set image")
}
}
func removeImageOverMyMenuItem(index:Int) {
if index>=0 && index<self.menuItems.count {
if let bgImage = self.menuItems[index].viewWithTag(9999) {
bgImage.fadeOut(completion: {
(finished: Bool) -> Void in
if finished {
bgImage.removeFromSuperview()
}
})
}
}
}
}
extension UIDevice {
var iPhone: Bool {
return UIDevice().userInterfaceIdiom == .phone
}
enum ScreenType: String {
case iPhone4
case iPhone5
case iPhone6
case iPhone6Plus
case unknown
}
var screenType: ScreenType {
guard iPhone else { return .unknown }
switch UIScreen.main.nativeBounds.height {
case 960:
return .iPhone4
case 1136:
return .iPhone5
case 1334:
return .iPhone6
case 2208:
return .iPhone6Plus
default:
return .unknown
}
}
}
You can easily use to add an image in viewDidLoad():
pageMenu = CAPSPageMenu(viewControllers: controllerArray, frame: CGRect(origin: CGPoint(x: 0,y :70), size: CGSize(width: self.view.frame.width, height: self.view.frame.height)), pageMenuOptions: menuParam)
pageMenu?.addImageOverMyMenuItem(index: 0, imageName: "detail.png")
pageMenu?.addImageOverMyMenuItem(index: 1, imageName: "gallery.png")
pageMenu?.addImageOverMyMenuItem(index: 2, imageName: "time.png")
pageMenu?.addImageOverMyMenuItem(index: 3, imageName: "map.png")
Result :

Related

Drag to dismiss a UIPresentationController

I have made a UIPresentationController that fits any view controller and shows up on half of the screen using this tutorial. Now I would love to add drag to dismiss to this. I'm trying to have the drag feel natural and responsive like the drag experience for "Top Stories" on the Apple iOS 13 stocks app. I thought the iOS 13 modal drag to dismiss would get carried over but it doesn't to this controller but it doesn't.
Every bit of code and tutorial I found had a bad dragging experience. Does anyone know how to do this? I've been trying / searching for the past week. Thank you in advance
Here's my code for the presentation controller
class SlideUpPresentationController: UIPresentationController {
// MARK: - Variables
private var dimmingView: UIView!
//MARK: - View functions
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
setupDimmingView()
}
override func containerViewWillLayoutSubviews() {
presentedView?.frame = frameOfPresentedViewInContainerView
}
override var frameOfPresentedViewInContainerView: CGRect {
guard let container = containerView else { return super.frameOfPresentedViewInContainerView }
let width = container.bounds.size.width
let height : CGFloat = 300.0
return CGRect(x: 0, y: container.bounds.size.height - height, width: width, height: height)
}
override func presentationTransitionWillBegin() {
guard let dimmingView = dimmingView else { return }
containerView?.insertSubview(dimmingView, at: 0)
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|[dimmingView]|",
options: [],
metrics: nil,
views: ["dimmingView": dimmingView]))
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|[dimmingView]|",
options: [],
metrics: nil,
views: ["dimmingView": dimmingView]))
guard let coordinator = presentedViewController.transitionCoordinator else {
dimmingView.alpha = 1.0
return
}
coordinator.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 1.0
})
}
override func dismissalTransitionWillBegin() {
guard let coordinator = presentedViewController.transitionCoordinator else {
dimmingView.alpha = 0.0
return
}
coordinator.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 0.0
})
}
func setupDimmingView() {
dimmingView = UIView()
dimmingView.translatesAutoresizingMaskIntoConstraints = false
dimmingView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
dimmingView.alpha = 0.0
let recognizer = UITapGestureRecognizer(target: self,
action: #selector(handleTap(recognizer:)))
dimmingView.addGestureRecognizer(recognizer)
}
#objc func handleTap(recognizer: UITapGestureRecognizer) {
presentingViewController.dismiss(animated: true)
}
}
As your description about the dragging experience you wanted is not that clear, hope I didn't get you wrong.
I'm trying to have the drag feel natural and responsive like the drag experience for "Top Stories" on the Apple iOS 13 stocks app.
What I get is, you want to be able to drag the presented view, dismiss it if it reach certain point, else go back to its original position (and of coz you can bring the view to any position you wanted).
To achieve this, we can add a UIPanGesture to the presentedViewController, then
move the presentedView according to the gesture
dismiss / move back the presentedView
class SlideUpPresentationController: UIPresentationController {
// MARK: - Variables
private var dimmingView: UIView!
private var originalX: CGFloat = 0
//MARK: - View functions
override init(presentedViewController: UIViewController, presenting presentingViewController: UIViewController?) {
super.init(presentedViewController: presentedViewController, presenting: presentingViewController)
setupDimmingView()
}
override func containerViewWillLayoutSubviews() {
presentedView?.frame = frameOfPresentedViewInContainerView
}
override var frameOfPresentedViewInContainerView: CGRect {
guard let container = containerView else { return super.frameOfPresentedViewInContainerView }
let width = container.bounds.size.width
let height : CGFloat = 300.0
return CGRect(x: 0, y: container.bounds.size.height - height, width: width, height: height)
}
override func presentationTransitionWillBegin() {
guard let dimmingView = dimmingView else { return }
containerView?.insertSubview(dimmingView, at: 0)
// add PanGestureRecognizer for dragging the presented view controller
let viewPan = UIPanGestureRecognizer(target: self, action: #selector(viewPanned(_:)))
containerView?.addGestureRecognizer(viewPan)
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|[dimmingView]|", options: [], metrics: nil, views: ["dimmingView": dimmingView]))
NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|[dimmingView]|", options: [], metrics: nil, views: ["dimmingView": dimmingView]))
guard let coordinator = presentedViewController.transitionCoordinator else {
dimmingView.alpha = 1.0
return
}
coordinator.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 1.0
})
}
#objc private func viewPanned(_ sender: UIPanGestureRecognizer) {
// how far the pan gesture translated
let translate = sender.translation(in: self.presentedView)
switch sender.state {
case .began:
originalX = presentedViewController.view.frame.origin.x
case .changed:
// move the presentedView according to pan gesture
// prevent it from moving too far to the right
if originalX + translate.x < 0 {
presentedViewController.view.frame.origin.x = originalX + translate.x
}
case .ended:
let presentedViewWidth = presentedViewController.view.frame.width
let newX = presentedViewController.view.frame.origin.x
// if the presentedView move more than 0.75 of the presentedView's width, dimiss it, else bring it back to original position
if presentedViewWidth * 0.75 + newX > 0 {
setBackToOriginalPosition()
} else {
moveAndDismissPresentedView()
}
default:
break
}
}
private func setBackToOriginalPosition() {
// ensure no pending layout change in presentedView
presentedViewController.view.layoutIfNeeded()
UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseIn, animations: {
self.presentedViewController.view.frame.origin.x = self.originalX
self.presentedViewController.view.layoutIfNeeded()
}, completion: nil)
}
private func moveAndDismissPresentedView() {
// ensure no pending layout change in presentedView
presentedViewController.view.layoutIfNeeded()
UIView.animate(withDuration: 0.25, delay: 0.0, options: .curveEaseIn, animations: {
self.presentedViewController.view.frame.origin.x = -self.presentedViewController.view.frame.width
self.presentedViewController.view.layoutIfNeeded()
}, completion: { _ in
// dimiss when the view is completely move outside the screen
self.presentingViewController.dismiss(animated: true, completion: nil)
})
}
override func dismissalTransitionWillBegin() {
guard let coordinator = presentedViewController.transitionCoordinator else {
dimmingView.alpha = 0.0
return
}
coordinator.animate(alongsideTransition: { _ in
self.dimmingView.alpha = 0.0
})
}
func setupDimmingView() {
dimmingView = UIView()
dimmingView.translatesAutoresizingMaskIntoConstraints = false
dimmingView.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
dimmingView.alpha = 0.0
let recognizer = UITapGestureRecognizer(target: self,
action: #selector(handleTap(recognizer:)))
dimmingView.addGestureRecognizer(recognizer)
}
#objc func handleTap(recognizer: UITapGestureRecognizer) {
presentingViewController.dismiss(animated: true)
}
}
The above code is just an example based on the code you provide, but I hope that explain what's happening under the hood of what you called a drag experience. Hope this helps ;)
Here is the example result:
via GIPHY

Manage Keyboard in Chat View

I have a controller like chat view, with one textfield and button and table view. I want to when user tap to textfield textfield go up and scroll to end of list. there is my code :
#objc func keyboardWillChangeFrame(_ notification: Notification) {
let keyboardFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameEndUserInfoKey]! as AnyObject).cgRectValue
print("*****************")
print((keyboardFrame?.height)!)
//emoji keyboard size is 258
if (keyboardFrame?.height)! == 258 {
textBackViewBottom.constant = 52
}
else {
textBackViewBottom.constant = 10
}
}
#objc func keyboardWillShow(_ notification: Notification) {
// Check for double invocation
if _keyboardShown {
return
}
_keyboardShown = true
// Reducing size of table
let baseView = self.view
let keyboardFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey]! as AnyObject).cgRectValue
print("////////////////////")
print((keyboardFrame?.height)!)
let keyboardDuration = ((notification as NSNotification).userInfo![UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue
let visibleRows = tableView.indexPathsForVisibleRows
var lastIndexPath : IndexPath? = nil
if (visibleRows != nil) && visibleRows!.count > 0 {
lastIndexPath = visibleRows![visibleRows!.count-1] as IndexPath
}
UIView.animate(withDuration: keyboardDuration!, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
baseView!.frame = CGRect(x: baseView!.frame.origin.x, y: baseView!.frame.origin.y, width: baseView!.frame.size.width, height: baseView!.frame.size.height - (keyboardFrame?.size.height)!)
}, completion: {
(finished: Bool) in
if lastIndexPath != nil {
// Scroll down the table so that the last
// visible row remains visible
self.tableView.scrollToRow(at: lastIndexPath!, at: UITableViewScrollPosition.bottom, animated: true)
}
})
}
#objc func keyboardWillHide(_ notification: Notification) {
// Check for double invocation
if !_keyboardShown {
return
}
_keyboardShown = false
// Expanding size of table
//
let baseView = self.view
let keyboardFrame = ((notification as NSNotification).userInfo![UIKeyboardFrameBeginUserInfoKey]! as AnyObject).cgRectValue
let keyboardDuration = ((notification as NSNotification).userInfo![UIKeyboardAnimationDurationUserInfoKey]! as AnyObject).doubleValue
UIView.animate(withDuration: keyboardDuration!, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
baseView!.frame = CGRect(x: baseView!.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.size.width, height: self.view.frame.size.height + (keyboardFrame?.size.height)!)
}, completion: nil)
}
every thing work well with Iphone default keyboard, but when I'm using custom keyboard like Swiftkey my code is wrong and view broken.
How can get Update view when keyboard size and keyboard type change.
thanks for reply.

UICollectionView show hide animation issue

I am getting animation issue while hiding the UICollectionView. Show animation works fine but when I do the hide animation, it immediately hides the collection view without animation. This is the code :
#objc func openMenu(sender: UIButton) {
if sender.tag == 1 {
self.buttonView.tag = 2
self.arrow.image = UIImage(named: "arrowUp.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = UIScreen.main.bounds.size.height - self.frame.size.height
}, completion: { _ in
})
} else {
self.buttonView.tag = 1
self.arrow.image = UIImage(named: "arrowDown.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = 0
}, completion: { _ in
})
}
}
Output :
The strange thing is, I replaced the collection view with a simple UIView and it works fine. Bottom to top animation works perfectly. Code :
#objc func openMenu(sender: UIButton) {
if sender.tag == 1 {
self.buttonView.tag = 2
self.arrow.image = UIImage(named: "arrowUp.png")
UIView.animate(withDuration: 0.7, animations: {
self.testView.frame.size.height = UIScreen.main.bounds.size.height - self.frame.size.height
}, completion: { _ in
})
} else {
self.buttonView.tag = 1
self.arrow.image = UIImage(named: "arrowDown.png")
UIView.animate(withDuration: 0.7, animations: {
self.testView.frame.size.height = 0
}, completion: { _ in
})
}
}
Output :
Question : Why doesn't that work for UICollectionView ?
Initialisation :
UICollectionView :
self.moduleView = ModulesCollectionView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 0), collectionViewLayout: UICollectionViewLayout())
self.parentView.addSubView(self.moduleView)
UIView :
self.testView = UIView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.size.width, height: 0))
self.parentView.addSubView(self.testView)
You need to use layoutSubViews() method for proper animation. Please change your code as below :
#objc func openMenu(sender: UIButton) {
if sender.tag == 1 {
self.buttonView.tag = 2
self.arrow.image = UIImage(named: "arrowUp.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = UIScreen.main.bounds.size.height - self.frame.size.height
// Add this line
self.moduleView.layoutSubviews()
}, completion: { _ in
})
} else {
self.buttonView.tag = 1
self.arrow.image = UIImage(named: "arrowDown.png")
UIView.animate(withDuration: 0.7, animations: {
self.moduleView.frame.size.height = 0
// Add this line
self.moduleView.layoutSubviews()
}, completion: { _ in
})
}
}

Swift UITabBarController hide with animation

I'm trying to add animation to my tabBarController when hidden. Im able to accomplish this effect with the navigationBarController by using self.navigationController?.isNavigationBarHidden = true. I'm able to hide the tabBar by using self.tabBarController?.tabBar.isHidden = true but i do not get the animation how can I do this thank you in advance.
You could change the tab bar's frame inside an animation, so something like:
func hideTabBar() {
var frame = self.tabBarController?.tabBar.frame
frame?.origin.y = self.view.frame.size.height + (frame?.size.height)!
UIView.animate(withDuration: 0.5, animations: {
self.tabBarController?.tabBar.frame = frame!
})
}
func showTabBar() {
var frame = self.tabBarController?.tabBar.frame
frame?.origin.y = self.view.frame.size.height - (frame?.size.height)!
UIView.animate(withDuration: 0.5, animations: {
self.tabBarController?.tabBar.frame = frame!
})
}
Which sets the tab bar just below the visible screen, so that it slides up/down from the bottom.
I've developed a util extension for UIViewController
Swift 4 compatible:
extension UIViewController {
func setTabBarHidden(_ hidden: Bool, animated: Bool = true, duration: TimeInterval = 0.3) {
if animated {
if let frame = self.tabBarController?.tabBar.frame {
let factor: CGFloat = hidden ? 1 : -1
let y = frame.origin.y + (frame.size.height * factor)
UIView.animate(withDuration: duration, animations: {
self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: frame.height)
})
return
}
}
self.tabBarController?.tabBar.isHidden = hidden
}
}
Improvement of the response of #Luca Davanzo. If the bar is already hidden, it will continue hiding it and moving it lower. Also get rid of the return, so the state of the tabbar.hidden changes when the animation happens.
So I added a check:
extension UIViewController {
func setTabBarHidden(_ hidden: Bool, animated: Bool = true, duration: TimeInterval = 0.5) {
if self.tabBarController?.tabBar.isHidden != hidden{
if animated {
//Show the tabbar before the animation in case it has to appear
if (self.tabBarController?.tabBar.isHidden)!{
self.tabBarController?.tabBar.isHidden = hidden
}
if let frame = self.tabBarController?.tabBar.frame {
let factor: CGFloat = hidden ? 1 : -1
let y = frame.origin.y + (frame.size.height * factor)
UIView.animate(withDuration: duration, animations: {
self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: y, width: frame.width, height: frame.height)
}) { (bool) in
//hide the tabbar after the animation in case ti has to be hidden
if (!(self.tabBarController?.tabBar.isHidden)!){
self.tabBarController?.tabBar.isHidden = hidden
}
}
}
}
}
}
}
In case if you need to toggle it from hide to visible and vice versa:
func toggleTabbar() {
guard var frame = tabBarController?.tabBar.frame else { return }
let hidden = frame.origin.y == view.frame.size.height
frame.origin.y = hidden ? view.frame.size.height - frame.size.height : view.frame.size.height
UIView.animate(withDuration: 0.3) {
self.tabBarController?.tabBar.frame = frame
}
}
Swift 4 solution:
tabBarController?.tabBar.isHidden = true
UIView.transition(with: tabBarController!.view, duration: 0.35, options: .transitionCrossDissolve, animations: nil)
Here is a simple extension :
func setTabBar(hidden:Bool) {
guard let frame = self.tabBarController?.tabBar.frame else {return }
if hidden {
UIView.animate(withDuration: 0.3, animations: {
self.tabBarController?.tabBar.frame = CGRect(x: frame.origin.x, y: frame.origin.y + frame.height, width: frame.width, height: frame.height)
})
}else {
UIView.animate(withDuration: 0.3, animations: {
self.tabBarController?.tabBar.frame = UITabBarController().tabBar.frame
})
}
}
So I've been playing around for 3 days with this now, finding out that the one that worked for me in my code was Adriana's post from 14th Sept 2018. But I was not sure how to use the coding once copied into my Project. So, after much experimenting I found that the way I could use this func was to put the following into into the respective swipe actions.
setTabBarHidden(false)
setTabBarHidden(true)
My next step is to try to get the swipe actions working while using UIScrollView in the same UIView at the same time.
You have to add UIView transitionWithView class func
Swift 2
func hideTabBarWithAnimation() -> () {
UIView.transitionWithView(tableView, duration: 1.0, options: .TransitionCrossDissolve, animations: { () -> Void in
self.tabBarController?.tabBar.hidden = true
}, completion: nil)
}
Swift 3, 4, 5
func hideTabBarWithAnimation() -> () {
UIView.transition(with: tableView, duration: 1.0, options: .transitionCrossDissolve, animations: { () -> Void in
self.tabBarController?.tabBar.isHidden = true
}, completion: nil)
}

Vanishing popup alert view

I'd like to popup a view with a single label in it that disappears slowly within one second to inform the user about a choice he made, an update occurred or whatever.
I use animatewithduration, but because they may be many different alerts, I'd like to create a class to avoid creating view, label and func in any UIViewController that may display that kind of alert ... Kind of :
let doneAlert = PopUpAlert(parentView : self, textAlert : "You're done")
where parentView in the view where I want the textAlert to be displayed and then when needed:
doneAlert.display()
Here's the class I wrote :
class PopUpAlert: UIView {
convenience init(parentView : UIView,textAlert : String) {
self.init(frame: CGRect(x: 0, y: 0, width: 200, height: 150))
self.alpha = 0
self.center = parentView.center
let popUpLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 200, height: 150))
popUpLabel.center = self.center
popUpLabel.text = textAlert
self.addSubview(popUpLabel)
parentView.addSubview(self)
}
func display() {
PopUpAlert.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.alpha = 1.0
}, completion: nil)
PopUpAlert.animateWithDuration(1.0, delay: 0.5, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 0.0
}, completion: nil)
}
}
And here's the way I use it :
class CarteVC: UIViewController {
var daddy : RootViewController?
var goAlert : PopUpAlert?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
goAlert = PopUpAlert(parentView: mapView, textAlert: "On the way ....")
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
let bb = UIBarButtonItem(title: "< List", style: .Plain, target: papa!, action: "pred")
bb.tintColor = UIColor.lightGrayColor()
daddy!.navigationItem.leftBarButtonItem = bb
daddy!.navigationItem.rightBarButtonItem = nil
goAlert!.display()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
Nothing is displayed.
If you want to just alert user and disappear in one second than i would suggest you to use Toast Swift
https://github.com/scalessec/Toast-Swift
Here is how you make the toast
self.view.makeToast("Testing Toast")
// specific duration and position
self.view.makeToast("Testing Toast with duration and position", duration: 3.0, position: .Top)
// toast with image and all possible
self.view.makeToast("testing toast image and all possible ", duration: 2.0, position: CGPoint(x: 110.0, y: 110.0), title: "Toast Title", image: UIImage(named: "toast.png"), style:nil) { (didTap: Bool) -> Void in
if didTap {
print("with tap")
} else {
print("without tap")
}
}
The pb came from centering the label inside the view ... Here's the class and works perfectly fine !!! :
class PopUpAlert: UIView {
convenience init(parentView : UIView,textAlert : String) {
self.init(parentView: parentView,textAlert: textAlert,background: UIColor.darkGrayColor(),foreground: UIColor.whiteColor())
}
convenience init(parentView : UIView,textAlert : String, background : UIColor) {
self.init(parentView: parentView,textAlert: textAlert,background: background,foreground: UIColor.whiteColor())
}
convenience init(parentView : UIView,textAlert : String, foreground : UIColor) {
self.init(parentView: parentView,textAlert: textAlert,background: UIColor.darkGrayColor(),foreground: foreground)
}
convenience init(parentView : UIView,textAlert : String, background : UIColor, foreground : UIColor) {
self.init(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
self.alpha = 0
self.backgroundColor = background
self.layer.cornerRadius = 5
self.layer.masksToBounds = true
self.center = (parentView.superview ?? parentView).center
let popUpLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 150, height: 40))
popUpLabel.textAlignment = .Center
popUpLabel.textColor = foreground
popUpLabel.text = textAlert
self.addSubview(popUpLabel)
parentView.addSubview(self)
}
deinit {
self.removeFromSuperview()
}
func display() {
PopUpAlert.animateWithDuration(0.5, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.alpha = 0.85
}, completion: nil)
PopUpAlert.animateWithDuration(1.0, delay: 0.7, options: UIViewAnimationOptions.CurveEaseIn, animations: {
self.alpha = 0.0
}, completion: nil)
}

Resources