I have the following swift code and what i am trying to achieve is a segue that slides off the top. I want the secondVCView to be below the firstVCView and for the firstVCView to slide off displaying the secondVCView.
Currently there is no animation and it just flashes to the secondVCView.
Many Thanks
import UIKit
class TopToBottomSegue: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
var firstVCView = self.sourceViewController.view as UIView!
var secondVCView = self.destinationViewController.view as UIView!
// Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(0, 0, screenWidth, screenHeight)
// Access the app's key window and insert the destination view below the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, belowSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(0.4, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, screenHeight)
//secondVCView.frame = CGRectOffset(secondVCView.frame, -screenWidth, 0.0)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
animated: false,
completion: nil)
}
}
}
As far as I know you need to call layoutIfNeed inside animateWithduration block in order to get a smooth animation.
Greetings
Im not sure if this is the correct way to do this but i managed to get it working by inserting both views.
L
--
import UIKit
class TopToBottomSegue: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
let firstVCView = self.sourceViewController.view as UIView!
let secondVCView = self.destinationViewController.view as UIView!
// Get the screen width, height and status bar height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
let statusBarHeight = self.statusBarHeight()
// Specify the initial position of both views.
secondVCView.frame = CGRectMake(0.0, 0.0, screenWidth, screenHeight)
firstVCView.frame = CGRectMake(0.0, statusBarHeight, screenWidth, screenHeight)
// Access the app's key window and insert the destination view below the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(firstVCView, aboveSubview: secondVCView)
window?.insertSubview(secondVCView, belowSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(0.3, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, screenHeight)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as UIViewController,
animated: false,
completion: nil)
}
}
func statusBarHeight() -> CGFloat {
let statusBarSize = UIApplication.sharedApplication().statusBarFrame.size
return Swift.min(statusBarSize.width, statusBarSize.height)
}
}
Related
I'm trying to learn basic iOS Swift3 and using the storyboard method. I was working through the code in the tutorial on this website.
Having created the storyboard links for FirstCustomSegue, I code as follows; I have added comments for all 6 errors:
class FirstCustomSegue: UIStoryboardSegue {
override func perform() {
// Value of type 'FirstCustomSegue' has no member 'sourceGameViewController'
var firstVCView = self.sourceGameViewController.view as UIView!
var secondVCView = self.destinationGameViewController.view as UIView!
// Cannot call value of non-function type 'UIScreen'
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
secondVCView.frame = CGRectMake(0.0, screenHeight, screenWidth, screenHeight)
// Cannot call value of non-function type 'UIApplication'
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// Value of type 'FirstCustomSegue' has no member 'sourceGameViewController' (This is in the (Finished) line, of course)
UIView.animateWithDuration(0.4, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, -screenHeight)
secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, -screenHeight)
}) { (Finished) -> Void inself.sourceGameViewController.presentGameViewController(self.destinationGameViewController as UIViewController,
animated: false,
completion: nil)
}
}
}
Looks to me as though there's a missing connection somewhere, but I can't find it. Perhaps some of it is a change in iOS10? Some searching has suggested that this may be the problem with the UIScreen.mainScreen() bits, but I can't find anything that resolves the problems.
I rewrote your code into Swift 3.0 style. But do you use Xcode 8? If you use Xcode 8, the compiler may help you to fix syntax errors.
class FirstCustomSegue: UIStoryboardSegue {
override func perform() {
let firstVCView: UIView = self.source.view
let secondVCView: UIView = self.destination.view
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
secondVCView.frame = CGRect(x: 0.0, y: screenHeight, width: screenWidth, height: screenHeight)
let window = UIApplication.shared.keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
UIView.animate(withDuration: 0.4, animations: {
firstVCView.frame = firstVCView.frame.offsetBy(dx: 0.0, dy: -screenHeight)
secondVCView.frame = secondVCView.frame.offsetBy(dx: 0.0, dy: -screenHeight)
}, completion: { [unowned self] finished in
self.source.present(self.destination, animated: false, completion: nil)
})
}
}
You can also convert your code into latest Swift syntax by yourself.
Edit > Convert > To Current Swift Syntax...
https://i.stack.imgur.com/niayG.png
You need to use
UIApplication.shared
and
UIScreen.main
in Swift 3. (Can't comment yet.)
The UITabBar disappears after I execute a custom segue.
Two views are embedded in a UITabBar Controller
First View Before Segue:
Second View After Segue:
First View After Segue:
Main Storyboard:
Custom Segue Code:
import UIKit
class CustomPushSegue: UIStoryboardSegue {
override func perform(){
// Assign the source and destination views to local variables.
let firstVCView = self.sourceViewController.view as UIView!
let secondVCView = self.destinationViewController.view as UIView!
// Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(screenWidth, 0.0, screenWidth, screenHeight)
//Insert the destination view above the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(0.35, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, -screenWidth, 0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, -screenWidth, 0.0)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as UIViewController, animated: false, completion: nil)
}
}
}
Custom Unwind Segue:
import UIKit
class CustomPushUnwindSegue: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
let secondVCView = self.sourceViewController.view as UIView!
let firstVCView = self.destinationViewController.view as UIView!
//Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(0.0, 0.0, screenWidth, screenHeight)
//Insert the destination view above the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(firstVCView, aboveSubview: secondVCView)
// Animate the transition.
UIView.animateWithDuration(0.35, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, screenWidth, 0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, screenWidth, 0.0)
}) { (Finished) -> Void in
self.sourceViewController.dismissViewControllerAnimated(false, completion: nil)
}
}
}
I am attempting to segue by having the source view controller go from the top to bottom. I can get the transition to go from top to bottom, but as the transition is happening, there is a black rectangle that goes from top to bottom. And once that's finished, the destination view controller pops up. Anybody know how to solve this problem? I am using this tutorial: http://www.appcoda.com/custom-segue-animations/ and changing bits and piece of it to do what I want it to do.
import UIKit
class FirstCustomSegue: UIStoryboardSegue {
override func perform() {
var firstVCView = self.sourceViewController.view as UIView!
var secondVCView = self.destinationViewController.view as UIView!
// Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(0.0, 0, screenWidth, screenHeight)
// Access the app's key window and insert the destination view above the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(2, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, screenHeight)
secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, screenHeight)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
animated: false,
completion: nil)
}
}
}
Update your code like this, Is it working correctly now ?
secondVCView.frame = CGRectMake(0.0, -screenHeight, screenWidth, screenHeight)
For those who are looking for the full solution in Swift 4:
override func perform() {
let firstVCView = self.source.view
let secondVCView = self.destination.view
// Get the screen width and height.
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
// Specify the initial position of the destination view.
secondVCView!.frame = CGRect(x: 0, y: -screenHeight, width: screenWidth, height: screenHeight)
// Access the app's key window and insert the destination view above the current (source) one.
let window = UIApplication.shared.keyWindow
window?.insertSubview(secondVCView!, aboveSubview: firstVCView!)
// Animate the transition.
UIView.animate(withDuration: 1, animations: { () -> Void in
firstVCView?.frame = (firstVCView?.frame.offsetBy(dx: 0, dy: screenHeight))!
secondVCView?.frame = (secondVCView?.frame.offsetBy(dx: 0, dy: screenHeight))!
}) { (finished) -> Void in
self.source.present(self.destination, animated: false, completion: nil)
}
}
I want to "slide out" my view controller above the destinationViewController with a segue. This is my code:
override func perform()
{
let src = self.sourceViewController
let dst = self.destinationViewController
dst.view.superview?.insertSubview(src.view, aboveSubview: dst.view)
src.view.transform = CGAffineTransformMakeTranslation(0, 0)
UIView.animateWithDuration(0.25,
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
src.view.transform = CGAffineTransformMakeTranslation(src.view.frame.size.width * -1, 0)
},
completion: { finished in
src.presentViewController(dst, animated: false, completion: nil)
}
)
}
The slide looks good, however the destinationViewController is all black during the animation, when the animation is completed the destinationViewController is shown correctly.
How can I make it display during segue animation?
EDIT:
solved it:
override func perform()
{
let src = self.sourceViewController
let dst = self.destinationViewController
src.view.superview?.insertSubview(dst.view, belowSubview: src.view)
dst.view.transform = CGAffineTransformMakeTranslation(0, 0)
UIView.animateWithDuration(0.25,
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
src.view.transform = CGAffineTransformMakeTranslation(src.view.frame.size.width * -1, 0)
},
completion: { finished in
src.presentViewController(dst, animated: false, completion: nil)
}
)
}
Try this:
class FirstCustomSegue: UIStoryboardSegue {
override func perform() {
// Assign the source and destination views to local variables.
var firstVCView = self.sourceViewController.view as UIView!
var secondVCView = self.destinationViewController.view as UIView!
// Get the screen width and height.
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// Specify the initial position of the destination view.
secondVCView.frame = CGRectMake(screenWidth, 0.0, screenWidth, screenHeight)
// Access the app's key window and insert the destination view above the current (source) one.
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// Animate the transition.
UIView.animateWithDuration(0.4, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, -screenWidth, -0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, -screenWidth, -0.0)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController,
animated: false,
completion: nil)
}
}
}
Try to add a Storyboard ID to your ViewController.
I'm trying to make custom segue between two view controllers without any animation. Everything works as I expecting just console giving me following message:
2015-06-16 12:19:01.537 prototyp_2[42453:9048104] Unbalanced calls to
begin/end appearance transitions for .
Here is my code:
class Segue_forward: UIStoryboardSegue {
override func perform() {
// zdroj a destinace do lokálních proměnných
var firstVCView = self.sourceViewController.view as UIView!
var secondVCView = self.destinationViewController.view as UIView!
// rozměry displeje
let screenWidth = UIScreen.mainScreen().bounds.size.width
let screenHeight = UIScreen.mainScreen().bounds.size.height
// initial position of destination view
secondVCView.frame = CGRect(x: 0.0, y: 0.0, width: screenWidth, height: screenHeight)
// protože destination VC není subview okna aplikace tak to musime napravit
let window = UIApplication.sharedApplication().keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
// animace
UIView.animateWithDuration(0.0, animations: { () -> Void in
firstVCView.frame = CGRectOffset(firstVCView.frame, 0.0, 0.0)
secondVCView.frame = CGRectOffset(secondVCView.frame, 0.0, 0.0)
}) { (Finished) -> Void in
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController, animated: false, completion: nil)
}
}
}
And here is my action:
#IBAction func nextQuestion(sender: AnyObject) {
self.performSegueWithIdentifier("id_forwardSegue", sender: self)
}
Just do it without animation:
override func perform() {
self.sourceViewController.presentViewController(self.destinationViewController as! UIViewController, animated: false, completion: nil)
}
present the new UIViewController with the parentViewController:
self.sourceViewController.parentViewController?.presentViewController(YOUR_VIEW_CONTROLLER, animated: false, completion: nil)