Swift - Using a segue removes Top Navigation Bar - swift

I'm using the performSegue function built into XCode to transfer between two views. I originally go from the view with the navigation bar to one without a navigation bar and it works perfectly. When I go back to the view with the Navigation Bar, the Bar just disappears and everything just moves up to fit the screen.
performSegue(withIdentifier: "goToCameraSegue", sender: self)
performSegue(withIdentifier: "goToMainControllerSegue", sender: self)
I use these segues to transfer between the different views. I am also using a custom class to get the move the view from the right to left as design.
src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
dst.view.transform = CGAffineTransform(translationX: -src.view.frame.size.width, y: 0)
UIView.animate(withDuration: 0.25,
delay: 0.0,
options: .curveEaseInOut,
animations: {
dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
},
completion: { finished in
src.present(dst, animated: false, completion: nil)
}
)
}

Related

Problem with animation when using UIView.transition & UIView.AnimationOptions when transitioning between ViewControllers

I'm using Swift and attempting to transition between a Menu screen ViewController (LaunchViewController) and a Game ViewController (InGameViewController) using the below code. However, whilst the transition works okay, no matter what animation options I use (currently using .transitionCrossDissolve) the animation always appears from the top left expanding to fill the whole screen. I can change the duration and the animation adjusts as expected, but no matter what the UIView.AnimationOption I use it always uses the same animation.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "InGameViewController")
vc.view.frame = (self.view?.frame)!
vc.view.layoutIfNeeded()
UIView.transition(with: self.view!, duration: 0.3, options: .transitionCrossDissolve, animations: {
self.view?.window?.rootViewController = vc
}, completion: { (true) in
})
How can I make this transition animation as desired? Many thanks in advance
func changeRootViewControllerTo(_ controller: UIViewController, animated: Bool = false) {
UIApplication.shared.keyWindow?.rootViewController = controller
guard
animated,
let window = UIApplication.shared.keyWindow else {
return
}
UIView.transition(with: window,
duration: 0.3,
options: .transitionCrossDissolve,
animations: nil,
completion: nil)
}
In my case this works perfect. I don't think you need to add those lines
vc.view.frame = (self.view?.frame)!
vc.view.layoutIfNeeded()
and change self.view to window in transition method.

How to fix: UIView animations not restarting when returning to view controller

I have a view that starts animating when a ViewController first opens. It works fine on initial launch, but when returning to the view after leaving the animation does not restart. The views are embedded in a Navigation controller
I tried placing the animation in several locations, including viewWillAppear, viewDidAppear and viewWillLayoutSubviews
I've placed a breakpoint in viewDidAppear and it does step through the code, but the animation does not restart.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(true)
UIView.animate(withDuration: 20.0, delay: 0, options: [.autoreverse, .repeat, .curveLinear], animations: {
self.scrollingView.transform = CGAffineTransform(translationX: -350, y: 0)
}, completion: nil)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
scrollingView.layer.removeAllAnimations()
}
You need to return the scrollingView to its original position during the segue, because of the UINavigationController the 1st UIViewController does not go out of scope, aka it does not get instantiated again. Therefore when you come back to the 1st UIViewController, the scrollingView is still running the previous animation.
You need to restart the CGAffineTransform using the code below :
override func viewDidDisappear(_ animated: Bool) {
self.textView.transform = CGAffineTransform.identity
}

Segue transitions to the wrong page Swift Xcode

I am trying to create a series of pages that work in tandem using custom segues. These segues work fine until I have them execute in a certain series. From VC1 I go to VC2 via the default modal segue (it pops up over the original segue). Then, from VC2 I go to VC3 using a custom horizontal segue (code below). Finally, I go back from VC3 to VC1 using a custom unwind horizontal segue. The problem is that when I go back to VC1, VC2 appears instead. I checked and ViewDidLoad does not execute in VC2 when it appears, but I can still interact with it when triggered. My best guess as to what is happening is that VC2 covers VC1 so when I go back to VC1, VC2 is displayed on top of it. Even if this is the problem, I don't know how to fix it. Code below:
Horizontal Segue:
class HorizontalSegue: UIStoryboardSegue {
override func perform() {
let src = self.source as UIViewController
let dst = self.destination as UIViewController
src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
dst.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)
UIView.animate(withDuration: 0.2, delay: 0.0, options: [.curveEaseOut], animations: {
dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
},
completion: { finished in
src.present(dst, animated: false, completion: nil)
})
}
}
Unwind Horizontal Segue:
class UnwindHorizontalSegue: UIStoryboardSegue {
override func perform() {
let src = self.source as UIViewController
let dst = self.destination as UIViewController
src.view.superview?.insertSubview(dst.view, belowSubview: src.view)
src.view.transform = CGAffineTransform(translationX: 0, y: 0)
UIView.animate(withDuration: 0.2, delay: 0.0, options: [.curveEaseIn], animations: {
src.view.transform = CGAffineTransform(translationX: src.view.frame.size.width, y: 0)
},
completion: { finished in
src.dismiss(animated: false, completion: nil)
})
}
}
The first thing I noticed is that you said ViewDidLoad is not called for VC2. Please see if ViewDidAppear (or will appear) is being called instead.
ViewDidLoad is only called when the view loads (initially, when it wasn't there before). ViewDidAppear should fire always, when the view is brought into the user's screen.
After that, log dst in your custom UIStoryBoardSegue. If that's an instance of VC2, you are simply pushing the wrong view controller.
I also see you're using src.present and src.dismiss in your UIStoryboardSegue. This means you're not actually pushing views, but presenting them "on top" of an active view controller. Try to rethink that logic, since this is very much likely where the problem lies.
I would rather try and push the view controllers (normally, instead of 'presenting' them) and change the UIStoryboardSegue appearance to fake the animation if that's what you're after.

Transition to a new ViewController embedded in an UINavigationController causes animation problem

I use a rootViewController and I want to move to another ViewController. The transition to the newViewController works with that code.
A problem occurs when the newViewController is embedded in an UINavigationController. Then the navigation bar is animating during the animation and changes the position.
The navigation bar is animating from the top left to the correct position.
fileprivate func animateTransition(to newViewController: UIViewController) {
currentViewController.willMove(toParent: nil)
addChild(newViewController)
newViewController.view.frame = view.bounds
transition(from: currentViewController, to: newViewController, duration: 2, options: [.transitionCrossDissolve, .curveEaseOut], animations: {
self.currentViewController.removeFromParent()
newViewController.didMove(toParent: self)
self.currentViewController = newViewController
}, completion: nil)
}
How is it possible to move to another UINavigationController with a "fade" animation and how can the navigation bar be at the correct position right from the beginning of the animation?
First, you should move your view controller clean-up code call from the animations closure into the completion closure:
currentViewController.willMove(toParent: nil)
addChild(newViewController)
newViewController.view.frame = view.bounds
transition(from: currentViewController, to: newViewController, duration: 2, options: [.transitionCrossDissolve, .curveEaseOut], animations: {
// this is intentionally blank
}, completion: { _ in
self.currentViewController.removeFromParent()
newViewController.didMove(toParent: self)
self.currentViewController = newViewController
})
You don't want to indicate the transition is done until the animation is complete.
To the navigation bar issue, rather than letting transition(from:to:duration:...) handle the manipulation of the view controller hierarchy, you can add it to your view hierarchy and then animate the unhiding of it. Usually you'd use the .showHideTransitionViews option, but transition is still doing something curious with the appearance methods that is confusing the navigation controller, so it's best to just animate it yourself:
currentViewController.willMove(toParent: nil)
addChild(newViewController)
newViewController.view.frame = view.bounds
newViewController.view.alpha = 0
view.addSubview(newViewController.view)
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseOut, animations: {
newViewController.view.alpha = 1
}, completion: { _ in
self.currentViewController.view.removeFromSuperview()
self.currentViewController.removeFromParent()
newViewController.didMove(toParent: self)
self.currentViewController = newViewController
})
That will allow it to present the navigation bar correctly from the beginning and just fade it in.
try putting this underneath the class declaration of the newViewController
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.setNavigationBarHidden(false, animated: false)
}
if you already have a viewDidLoad() in your ViewController, then just use the last part.
If that doesn't work let me know.

How to hide the toolbar when web view is swiped without a navigation controller?

I'm using XCode 8 and Swift 3. I can't seem to find the answer.
I have a webView with a toolbar at the bottom, and I'd like to hide the toolbar when the webView is swiped, but hidesBarsOnSwipe only works if you have a navigation controller. I'm not using a navigation controller.
If I set toolBar.isHidden = true, the toolbar is hidden, but how do I unhide when user swipes up?
Try This code : Tested in Swift 3
#IBOutlet weak var myToolBar: UIToolbar!
override func viewDidLoad() {
super.viewDidLoad()
myToolBar.barTintColor = .red // Set any colour or leave that be.
}
func hideMyToolBar() {
UIView.animate(withDuration: 0.7, delay: 0.0, options: UIViewAnimationOptions.curveEaseOut, animations: {
self.myToolBar.frame = CGRect(x:0, y:self.view.frame.height + self.myToolBar.frame.height, width:self.view.frame.size.width, height: self.myToolBar.frame.height)
}, completion: nil)
}
func showMyToolBar() {
UIView.animate(withDuration: 0.7, delay: 0.0, options: UIViewAnimationOptions.curveEaseIn, animations: {
self.myToolBar.frame = CGRect(x:0, y:self.view.frame.height - self.myToolBar.frame.height, width:self.view.frame.size.width, height: self.myToolBar.frame.height)
}, completion: nil)
}
Note: I am using button action to hide and show toolbar. You have to implement swipe/tap gesture to hide and show toolbar.
Output: