Swift Switching To and FromTable ViewController Issue Using Custom Segue - ios

I have run into an issue when using a custom segue. I have two tableviews that I'm an trying to switch back and forth from. When I click on a cell in tableview1 it should take me to tableview2. I have a button on tableview2 that connects to the exit of the storyboard. From there it should take me back to tableview1 but whenever I press the button, the application crashes with a BAD_ACCESS error.
Here is my custom segue class:
class TableViewSegue: UIStoryboardSegue {
override func perform() {
scale()
}
func scale () {
let toViewcontroller = self.destination
let fromViewcontroller = self.source
let containerView = fromViewcontroller.view.superview
let originalCenter = fromViewcontroller.view.center
toViewcontroller.view.transform = CGAffineTransform(scaleX: 0.05, y: 0.05)
toViewcontroller.view.center = originalCenter
containerView?.addSubview(toViewcontroller.view)
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseInOut, animations: {
toViewcontroller.view.transform = CGAffineTransform.identity
}, completion: { success in
fromViewcontroller.present(toViewcontroller, animated: false, completion: nil) //The application crashes and highlights this line as the error.
})
}
}
I have implemented this method in my tableViewController1:
#IBAction func prepareForUnwind(segue: UIStoryboardSegue) {
}
Not sure why the tableview2 does not dismiss.
EDIT: The issue had to do with needing a navigation controller.

The problem is that you are presenting the toViewcontroller each time a segue is performed. So the app presents table2 over table1, and then tries again to present table1 over table2 on the unwind.
Modify your custom segue to check - essentially - which direction you're going:
class TableViewSegue: UIStoryboardSegue {
override func perform() {
scale()
}
func scale () {
let toViewcontroller = self.destination
let fromViewcontroller = self.source
let containerView = fromViewcontroller.view.superview
let originalCenter = fromViewcontroller.view.center
toViewcontroller.view.transform = CGAffineTransform(scaleX: 0.05, y: 0.05)
toViewcontroller.view.center = originalCenter
containerView?.addSubview(toViewcontroller.view)
let fromP = fromViewcontroller.presentingViewController
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseInOut, animations: {
toViewcontroller.view.transform = CGAffineTransform.identity
}, completion: { success in
// if nil, we are presenting a new VC
if fromP == nil {
fromViewcontroller.present(toViewcontroller, animated: false, completion: nil)
} else {
fromViewcontroller.dismiss(animated: false, completion: nil)
}
})
}
}
Note: This is assuming:
you are not trying to push/pop within a UINavigationController ... you'd need to add some other checks to handle that.
you are only going one-level-in, that is, you are not presenting, presenting, presenting, etc. and then trying to unwind.

Related

Button is not clickable in a child viewcontroller

I am trying to make a side menu which reacts to a hamburger icon clicked.
I created another storyboard with a ViewConroller which contains the TableView in it.
I created a ViewController for this storyboard ViewController.
In the First ViewController (which is not a container), I have the following code:
var menuVC: UIViewController!
var isExpanded = false
#IBAction func MenuTapped(_ sender: UIButton) {
isExpanded = !isExpanded
showMenuVC(shouldExpand: isExpanded)
}
func showMenuVC(shouldExpand: Bool) {
if shouldExpand {
// show menu
if menuVC == nil {
print ("ONLY ONCE")
let storyboard = UIStoryboard(name: "Menu", bundle: .main)
menuVC = storyboard.instantiateViewController(withIdentifier: "MenuSB") as! MenuVC
menuVC.view.frame = self.view.frame.offsetBy(dx: view.frame.width, dy: 0)
menuVC.willMove(toParent: self)
self.view.insertSubview(menuVC.view, at: 0)
self.addChild(menuVC)
menuVC.didMove(toParent: self)
}
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
self.view.frame.origin.x = 80 - self.view.frame.width
}, completion: nil)
} else {
// hide menu
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
self.view.frame.origin.x = 0
}, completion: nil)
}
}
The thing is, the TableView is not responding to anything. Not scrolling, not clicking. I also tried a UIButton and it is not clickable.
The problem is, that the first ViewController is active while the MenuVC is not.
It is important to have both of them active, since the hamburger icon in the first ViewController closes the menu, but I need the MenuVC to be active as well.
Any thoughts?
Try to replace this line:
self.view.insertSubview(menuVC.view, at: 0)
with this:
self.view.addSubview(menuVC.view)
since I have no idea about the subviews you have in self.view, because there might be some views on top of your menu which have isUserInteractionEnabled set to true

app crash when presenting view controller after loadViewIfNeed

I'm trying to present a view controller with custom animation, so I came up with this code. When I tried to present the view controller, I got no error but the app crashes. Can someone tell me why my app crashes?
My code looks like this
func presentLeftToRight<T>(viewName: String, class: T.Type) where T: DefaultView {
let presentView = self.storyboard?.instantiateViewController(withIdentifier: viewName) as! T
presentView.loadViewIfNeeded()
presentView.topContainer.alpha = 0
presentView.bgMenuView.alpha = 0
presentView.mainButton.alpha = 0
self.view.insertSubview(presentView.view, belowSubview: scrollView)
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.5, animations: {
self.scrollView.frame.origin.x = self.view.frame.width
}, completion: { _ in
self.present(presentView, animated: false, completion: nil)
})
}

Is it possible to create Custom Segue which transitions from right to left

I'm creating an iOS app with Swift and I'd like to create custom segue which transitions from right to left. The default transition way is from left to right but I do need to have the opposite way of transition. I just wrote the code like this.
class RightToLeftSegue: UIStoryboardSegue {
override func perform() {
let sourceViewController = self.sourceViewController
let destinationViewController = self.destinationViewController
let window = UIApplication.sharedApplication().keyWindow
window!.rootViewController = destinationViewController
window!.rootViewController = sourceViewController
UIView.transitionWithView(window!, duration: 0.5, options: .TransitionFlipFromLeft, animations: { window!.rootViewController = destinationViewController }, completion: { (finished: Bool) in })
}
}
But this just transitions flipping move. Any way I can do this? Thanks!
Try this
class RightToLeftSegue : UIStoryboardSegue {
override func perform() {
guard let navigationController = sourceViewController.navigationController else { return }
sourceViewController.view.superview?.addSubview(destinationViewController.view)
let frame = sourceViewController.view.frame
destinationViewController.view.frame = CGRectOffset(frame, -frame.size.width, 0.0)
UIView.animateWithDuration(0.5,
animations: {
self.sourceViewController.view.frame = CGRectOffset(frame, frame.size.width, 0.0)
self.destinationViewController.view.frame = frame
})
{ (finished: Bool) in
navigationController.rootViewController = self.destinationViewController
}
}
}
EDIT
Or this!
class RightToLeftSegue : UIStoryboardSegue {
override func perform() {
sourceViewController.navigationController?.viewControllers = [destinationViewController, sourceViewController]
sourceViewController.navigationController?.popViewControllerAnimated(true)
}
}

Dismissing using UIModalPresentationStyle.OverFullScreen results in black screen

I have a view controller (VCA) that modally presents another view controller VCB:
presentViewController(VCB, animated: true, completion: nil)
If VCB has a modalPresentationStyle = .OverFullScreen (same applies for .OverCurrentContext), why when it is dismissed:
dismissViewControllerAnimated(true, completion: nil)
does the following code when the transition is finished result in VCA turning black?
func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
let toVC = transitionContext.viewControllerForKey(UITransitionContextToViewContrllerKey)!
let fromVc = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey)!
var containerView = transitionContext.containerView()!
if presenting {
toVC.view.alpha = 0
containerView.insertSubview(toVC.view, aboveSubview: fromVC.view)
} else {
containerView.insertSubview(toVC.view, belowSubview: fromVC.view)
}
UIView.animateWithDuration(transitionDuration(transitionContext), delay: 0.0, options: [.CurveEaseInOut], animations: {
if self.presenting {
self.toVC.view.alpha = 1
} else {
self.fromVC.view.alpha = 0
}
} , completion: { finished in
self.transitionContext.completeTransition(true)
})
}
Is there a way to fix this without removing the line containerView.insertSubview(toVC.view, belowSubview: fromVC.view) or checking the value of fromVC.modalPresentationStyle before executing the above line? i.e. is there some parameter I can set in VCA's or VCB's initialiser?
Many thanks for any help.

Perform unwind-segue with custom-class

I do not want to use a NavigationController for this.
I have a Segue(Show(Push) with a custom class UIStoryboardSegue) between two ViewControllers. Now i want to "pop" the current ViewController, after some reading i think this is called "unwind segue".
I have a UIButton that is added with code during runtime. How to i add the unwind segue to this button?
How do i use my custom class for the unwind segue animation? :
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)
}
)
}

Resources