Custom Slide Segue - Xcode 8.0 Swift 3.0 - swift

What is the best way to create a custom segue that lets me press a button and then a view controller slides on. I have created a left to right segue but I want to make it go the other way. I have looked at some Youtube videos and this question but they don't show me what I want.
My code:
import UIKit
class SegueFromLeft: UIStoryboardSegue
{
override func perform()
{
let src = self.sourceViewController
let dst = self.destinationViewController
src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
dst.view.transform = CGAffineTransformMakeTranslation(-src.view.frame.size.width, 0)
UIView.animateWithDuration(0.25,
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
dst.view.transform = CGAffineTransformMakeTranslation(0, 0)
},
completion: { finished in
src.presentViewController(dst, animated: false, completion: nil)
}
)
}
}
Basically, I want to create a segue that goes from right to left.
Thanks
I am using Xcode 8.0 and Swift 3.0

Try this:
class SegueFromLeft: UIStoryboardSegue{
override func perform(){
let src=sourceViewController
let dst=destinationViewController
let slide_view=destinationViewController.view
src.view.addSubview(slide_view)
slide_view.transform=CGAffineTransform.init(translationX: src.view.frame.size.width, 0)
UIView.animateWithDuration(0.25,
delay: 0.0,
options: UIViewAnimationOptions.CurveEaseInOut,
animations: {
slide_view.transform=CGAffineTransform.identity
}, completion: {finished in
src.present(dst, animated: false, completion: nil)
slide_view.removeFromSuperview()
})
}
}

Swift 3.1:
class ProceedToAppStoryboardSegue: UIStoryboardSegue {
override func perform(){
let slideView = destination.view
source.view.addSubview(slideView!)
slideView?.transform = CGAffineTransform(translationX: source.view.frame.size.width, y: 0)
UIView.animate(withDuration: 0.25,
delay: 0.0,
options: UIViewAnimationOptions.curveEaseInOut,
animations: {
slideView?.transform = CGAffineTransform.identity
}, completion: { finished in
self.source.present(self.destination, animated: false, completion: nil)
slideView?.removeFromSuperview()
})
}
}

Related

How To Create Animation of Segue perform and unwind segue?

i am working on application where i am trying to call controllers with animations
second view controller with animations
like when i call second controller with segue
second controller come from right and first controller start moving to left
like android push pop animations
i make some code
class SegueFromRight: UIStoryboardSegue {
override func perform() {
let src = self.source
let dst = self.destination
src.view.superview?.insertSubview(dst.view, aboveSubview: src.view)
dst.view.transform = CGAffineTransform(translationX: src.view.frame.size.width*2, y: 0)
//Double the X-Axis
UIView.animate(withDuration: 0.25, delay: 0.0, options: UIView.AnimationOptions.curveEaseInOut, animations: {
dst.view.transform = CGAffineTransform(translationX: 0, y: 0)
}) { (finished) in
src.present(dst, animated: false, completion: nil)
}
}
}
but from this code new controller come from right i need to move current controller to move left too
if anyone can help
Try this code:
class CustomSegue: UIStoryboardSegue {
override func perform() {
let firstVCView: UIView = self.source.view
let secondVCView: UIView = self.destination.view
self.destination.modalPresentationStyle = .fullScreen
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
secondVCView.frame = CGRect(x: screenWidth, y: 0, width: screenWidth, height: screenHeight)
let window = UIApplication.shared.keyWindow
window?.insertSubview(secondVCView, aboveSubview: firstVCView)
UIView.animate(withDuration: 0.4, animations: { () -> Void in
firstVCView.frame = firstVCView.frame.offsetBy(dx: -screenWidth, dy: 0.0)
secondVCView.frame = secondVCView.frame.offsetBy(dx: -screenWidth, dy: 0.0)
}) { (Finished) -> Void in
self.source.present(self.destination as UIViewController,
animated: false,
completion: nil)
}
}
}
class CustomSegueUnwind: UIStoryboardSegue {
override func perform() {
let secondVCView: UIView = self.source.view
let firstVCView: UIView = self.destination.view
self.destination.modalPresentationStyle = .fullScreen
let screenWidth = UIScreen.main.bounds.size.width
let window = UIApplication.shared.keyWindow
window?.insertSubview(firstVCView, aboveSubview: secondVCView)
UIView.animate(withDuration: 0.4, animations: { () -> Void in
firstVCView.frame = firstVCView.frame.offsetBy(dx: screenWidth, dy: 0.0)
secondVCView.frame = secondVCView.frame.offsetBy(dx: screenWidth, dy: 0.0)
}) { (Finished) -> Void in
self.source.dismiss(animated: false, completion: nil)
}
}
}
Reference HERE for more details

Trying change Button Title and label.center.x in UIView.animate when press button but stuck. Why? Swift 4 Xcode 9.4

My Problem
I'm trying do some animation with label using UIView.animate(..) when touchInside button . Everything still be OK until I added a line: "self?.confirm.setTitle("Đăng nhập", for: .normal). The animation doesn't work.
My Will
I want the yellow underline below Đăng Ký switch to below Đăng nhập.
It good when code is
#IBAction func signUpAction(_ sender:Any?){
if (signup == false){
signup = true
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x -= (self?.underlineSignup.bounds.width)!
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
#IBAction func signInAction(_ sender:Any?){
if (signup == true){
signup = false
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x += (self?.underlineSignup.bounds.width)!
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
It work
But when I add .setTitle
#IBAction func signUpAction(_ sender:Any?){
if (signup == false){
signup = true
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x -= (self?.underlineSignup.bounds.width)!
self?.confirm.setTitle("Đăng ký", for: .normal)
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
#IBAction func signInAction(_ sender:Any?){
if (signup == true){
signup = false
UIView.animate(withDuration: 0.4, delay: 0, options: [.curveEaseIn], animations: {[weak self] in
self?.underlineSignup.center.x += (self?.underlineSignup.bounds.width)!
self?.confirm.setTitle("Đăng nhập", for: .normal)
self?.view.layoutIfNeeded()
}, completion: nil)
}
}
It stuck, only the title of button confirm change, the underline doesn't move
Please anyone can explain this situation.
EDIT:
The animation working but it's destination is always the first place which under Đăng ký ( animation come from left or right of it, the result always first place )
I think I knew how it is. Because in setTitle has updateFrame Constraintlayout of view. I have a contraintlayout when build button.
When I setTitles it reset the view using constraint.
That's what I think about this.
Try putting 'setTitle' into completion.
UIView.animate(withDuration: 0.15, delay: 0, options: .curveLinear, animations: {
self?.underlineSignup.center.x -= (self?.underlineSignup.bounds.width)!
self?.view.layoutIfNeeded()
}){
//completion
self?.confirm.setTitle("Đăng ký", for: .normal)
}

UIViewAnimation with constraint not working in Swift

I am trying to create an animation where I want to slide a uiview from right to left once parent UIViewController has loaded although I am able to display the view but the animation is not working. My code for animation:
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
view.isOpaque = false
UIView.animate(withDuration: 1.0, delay: 1.0, options: .curveEaseOut, animations: {
self.contentXConstraint.constant = 500
self.contentXConstraint.constant = 80
}) { (status) in
}
}
I have displayed the parent view controller as presented viewcontroller:
present(navController, animated: false, completion: nil)
You forgot self.view.layoutIfNeeded()
self.contentXConstraint.constant = 500
self.contentXConstraint.constant = 80
UIView.animate(withDuration: 1.0, delay: 1.0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}) { (status) in
}
from https://developer.apple.com/documentation/uikit/uiview/1622507-layoutifneeded
Use this method to force the view to update its layout immediately. When using Auto Layout, the layout engine updates the position of views as needed to satisfy changes in constraints
Move your animation code from viewDidAppear to viewDidLayoutSubviews
You need to add layoutIfNeeded() method after updating constraints
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
view.isOpaque = false
UIView.animate(withDuration: 1.0, delay: 1.0, options: .curveEaseOut, animations: {
self.contentXConstraint.constant = 500
self.contentXConstraint.constant = 80
self.view.layoutIfNeeded()
}) { (status) in
}
}

How to repeat flip animation?

I'm trying to create my own activity indicator view like twitch chat activity indicator view. But I've tried to use animate .repeat:
override func animate() {
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: [.repeat, .transitionFlipFromLeft], animations: {
self.flip()
}, completion: nil)
}
and also timer
let timer = Timer.init(timeInterval: 2, target: self, selector: #selector(flip), userInfo: nil, repeats: true)
Here is my flip() function
func flip() {
self.isFlipped = !self.isFlipped
let fromView = self.isFlipped ? self.view1 : self.view2
let toView = self.isFlipped ? self.view2 : self.view1
UIView.transition(from: fromView, to: toView, duration: 1, options: [.transitionFlipFromTop, .showHideTransitionViews], completion: nil)
}
But it did not work. I don't know what I missed. Can you guys help me please?

No buttons/labels/anything will re-appear after I set alpha back to 1.0

What I want: After the Viewcontroller is called, I want to fade in all my elements in this Viewcontroller, except for the background. The background must stay.
What goes wrong: As you see in my code, for something to fade in, it first needs to be removed. The remove part is doing great. But, when I want it to re-appear, nothing happens. When I use the print function to see the alpha of a random label, it is set to 1.0. I can not figure out what I am doing wrong.
This is my code:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
Removeeverything()
Fadein()
}
func Removeeverything() {
for view in self.view.subviews as [UIView] {
if let btn = view as? UIButton {
UIView.animateWithDuration(0.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
btn.alpha = 0.0
}, completion: nil)
}
}
for view in self.view.subviews as [UIView] {
if let btn = view as? UILabel {
UIView.animateWithDuration(0.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
btn.alpha = 0.0
}, completion: nil)
}
}
for view in self.view.subviews as [UIView] {
if let btn = view as? UIImageView {
UIView.animateWithDuration(0.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
btn.alpha = 0.0
}, completion: nil)
}
}
}
func Fadein() {
Backgrond.alpha = 1.0
for view in self.view.subviews as [UIView] {
if let btn = view as? UIButton {
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
btn.alpha = 1.0
}, completion: nil)
}
}
for view in self.view.subviews as [UIView] {
if let btn = view as? UILabel {
UIView.animateWithDuration(1.0, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
btn.alpha = 1.0
}, completion: nil)
}
}
for view in self.view.subviews as [UIView] {
if let btn = view as? UIImageView {
UIView.animateWithDuration(0.7, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: {
btn.alpha = 1.0
}, completion: nil)
}
}
}
I'd say that the problem is that UIView.animateWithDuration is executed asynchronous (that is - your fadeIn() function will execute before the animations in removeEverything() are complete).
Simply remove the UIView.animateWithDuration operations from your Removeeverything(). Since you've set the duration argument to 0.0 nothing will really change (except that the code should now work)
func removeEverything() {
for v in view.subviews.filter({ $0 is UIButton || $0 is UILabel || $0 is UIImageView }) {
v.alpha = 0
}
}
func fadeIn() {
// Background.alpha = 1.0
UIView.animateWithDuration(1.0, delay: 0, options: .CurveEaseIn, animations: {
for v in view.subviews.filter({ $0 is UIButton || $0 is UILabel }) {
v.alpha = 1
}
}, completion: nil)
UIView.animateWithDuration(0.7, delay: 0, options: .CurveEaseIn, animations: {
for v in view.subviews.filter({ $0 is UIImageView }) {
v.alpha = 1
}
}, completion: nil)
}
That code snippet should work as expected. I used the filter function on the array and got rid of a couple of unnecessary casts to make the code more readable. Hope it helps!
Just a thought, have you tried setting the alpha to something unrecognizably low like 0.01 rather than removing them entirely? You could also try matching the color of the button to the background and then fading it back in that way.
You may also need to call self.background.alpha or view.background.alpha
Also, you should really camel-case your function names.