UIView Animation is not working when adding ChildViewController - ios

I have a MasterViewController and I am adding a ChildViewController inside a MasterViewController. Inside MasterViewController I have made top button bar , and took a view as a Container view. In this container view I want to move my ChildViewControllers. And This will happen on button click in MasterViewController
This is how I am adding the ChildViewController
func addViewControllerAsChildViewController(childVC : UIViewController) {
oldVC = newVC
childVC.view.frame = viewContainer.bounds
childVC.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
addChildViewController(childVC)
childVC.didMove(toParentViewController: self)
// Where ViewContainer is dedicated area inside the MasterViewController
viewContainer.addSubview(childVC.view)
}
And these are my button clicks
#IBAction func onClickBtnNewList(_ sender: UIButton) {
if !(newVC is NewListVC) {
initNewListVC()
addViewControllerAsChildViewController(childVC: targetViewController)
}
UIView.animate(withDuration: 4000, animations: {
self.viewIndicators.frame = sender.frame.offsetBy(dx:0,dy:2)
})
}
#IBAction func onClickBtnSavedList(_ sender: UIButton) {
if !(newVC is SavedListVC) {
initSavedListVC()
addViewControllerAsChildViewController(childVC: targetViewController)
}
UIView.animate(withDuration:400, animations: {
self.viewIndicators.frame = sender.frame.offsetBy(dx:0,dy:2)
})
}
My ChildViewControllers gets inflated correctly. But Problem is on button Click there is a another view, which I am animating on click and moving it below the button. You can see I have used the following code in button click. The animation start and ended moving my related view to its starting position. and its not moving to my expected area see code below
UIView.animate(withDuration: 4000, animations: {
self.viewIndicators.frame = sender.frame.offsetBy(dx:0,dy:2)
})
but this is not working. But If I comment out following lines that are attaching ChildViewController , The animation do move smoothly and View moves to the target area
/*
if !(newVC is NewListVC) {
initNewListVC()
hideOrShowViewController(targetViewController: newVC!)
}
*/
Now do you have any idea why it is happening ?? what could be problem?
I am using Xcode 9 and swift 4 Please help

Related

Call API only once when adding/removing subview

I've a segmented control, clicking on segments shows views by adding view to a container view. When other segment control is clicked older view is removed and new view is added by using function given below. Adding VC in this way calls viewDidLoad where I fetch data from API. This calls API every time segment is clicked as VC is added. How do I prevent calling API every time view is added?
Is there any way we can hide old view instead of removing it, this will prevent instantiating VC every time a segment is clicked.
Alternatively is there any other better way to shows VCs on segment click?
#IBAction func show(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
let vc1 = VC1.instantiate()
self.cycleFromViewController(oldViewController: self.currentVC!, toViewController: vc1)
self.currentVC = vc1
case 1:
let vc2 = VC2.instantiate()
self.cycleFromViewController(oldViewController: self.currentVC!, toViewController: vc2)
self.currentVC = vc2
default:
break
}
}
func cycleFromViewController(oldViewController: UIViewController, toViewController newViewController: UIViewController) {
oldViewController.willMove(toParent: nil)
self.addChild(newViewController)
self.addSubview(subView: newViewController.view, toView:self.containerView!)
newViewController.view.alpha = 0
newViewController.view.layoutIfNeeded()
UIView.animate(withDuration: 0.5, animations: {
newViewController.view.alpha = 1
oldViewController.view.alpha = 0
},
completion: { finished in
oldViewController.view.removeFromSuperview()
oldViewController.removeFromParent()
newViewController.didMove(toParent: self)
})
}
Create
var vc1,vc2,currentVC:UIViewController?
Then inside viewDidLoad create and assign vc1 and vc2 and set currentVC = vc1
after that play with their view.isHidden

Present ViewControllers Modally inside Parent ViewController UIView

I have one main ViewController, which will render different views from other view controllers (mostly table views), by using addChild:Vc i can present and remove the child view, but the problem is it's a view hierarchy, so view layers will come over each other and every child view has a button which will dismiss itself and re-presents the previous view in view hierarchy. exactly like Navigation Bar back button.
So far what i have done is an UIViewController Extension which is:
func addChildVC(_ child: UIViewController,
centerWith center: CGPoint? = CGPoint(x: 0.0, y: 0.0),
insertInView insertIn: UIView? = nil,
transition: UIView.AnimationOptions? = [],
completion: ((Bool) -> Void)? = nil)
{
self.addChild(child)
if let center = center
{
child.view.center = center
}
if let insertIn = insertIn
{
insertIn.insertSubview(child.view, aboveSubview: insertIn.self)
} else {
self.view.addSubview(child.view)
}
child.didMove(toParent: self)
}
func removeChildVC()
{
willMove(toParent: nil)
view.removeFromSuperview()
removeFromParent()
}
You need a navigation for the contained vc
Step 1
Step 2 select the child vc and
Step 3
Now you can push and pop inside that child vc

How, during a segue, can an UIView remain on top of the segue animation?

I have a storyboard segue, and while showing the new view, I want an UIView to always stay on top, so the segue does not affect it. Tried animating insertSubview, but it does not have the push from bottom animation.
Here is some code I quickly whipped up showing two view controllers, the one you are going to and one from. I put the animation in a function called buttonPressed, but it should go whatever function that calls the transition. Rest of the code is pretty self explanatory.
For this to work both view controllers will need a view with same name (or different names but keep track of which is which), I use IBOutlet staticView. And then in interface builder make sure they have the same constraints or frame so that when you set on vc's static view to another it sticks to same spot.
class ViewControllerFrom: UIViewController {
#IBOutlet weak var staticView: UIView!
#IBAction func buttonPressed(_ sender: Any) {
let toVC = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "toVC") as! ViewControllerTo
//Add nextVC's view to ours as subview
self.view.addSubview(toVC.view)
//Set its starting height to be below current view.
toVC.view.frame = CGRect(x: 0, y: view.frame.height, width: view.frame.width, height: view.frame.height)
//This is important to make sure staticView stays in front of view animating in
view.bringSubview(toFront: staticView)
if toVC.staticView != nil {
toVC.staticView.isHidden = true
}
//I use animation duration 0.4, close to default animations by iOS.
UIView.animate(withDuration: 0.4, animations: {
toVC.view.frame.origin.y = 0
}, completion: { (success) in
if success {
//Now that view is in place, set static view from old vc to new vc and reshow it. Then do the actual presentation unanimated.
toVC.staticView.isHidden = false
toVC.staticView = self.staticView
self.present(toVC, animated: false, completion: nil)
}
})
}
}
class ViewControllerTo : UIViewController {
#IBOutlet weak var staticView: UIView!
}

Slide Out menu iOS showing Status Bar in iOS

I am using Swift 3 and xcode 8 to build a slide out menu for an iOS app (I don't want to use any open source library) so I had built it , I am facing two problems ,
1.If the center view has a navigation bar , then the side menu view is appearing beneath the navigation bar , I want it to start from the screen bounds.
2.The slide menu view also shows the carrier , time on top of the menu view , I want the behavior similar to google plus iOS app , where the menu loads on top of the home view.
Please find below the code I use to open the slide menu , I am not sure if the above issues are happening because I had added the menu view as a subview , if there is a better way to do it , kindly suggest.
Opening the menu view from the home view controller
let menuVC : MenuViewController = self.storyboard!.instantiateViewController(withIdentifier: "MenuViewController") as! MenuViewController
menuVC.delegate = self
self.view.addSubview(menuVC.view)
self.addChildViewController(menuVC)
menuVC.didMove(toParentViewController: self)
menuVC.view.layoutIfNeeded()
menuVC.view.frame=CGRect(x: 0 - UIScreen.main.bounds.size.width, y: 0, width: self.view.frame.width, height: self.view.frame.height);
UIView.animate(withDuration: 0.3, animations: { () -> Void in
menuVC.view.frame = self.view.frame
sender.isEnabled = true
}, completion:nil)
If you really want to view to be on top of the status bar and the navcontroller you can add it to the window:
UIApplication.shared.keyWindow?.addSubview(menuVC.view)
Note that the view is no longer a subview of the ViewController so you also need to manually dismiss it in deinit otherwise it will stay on screen even when the view controller goes away:
menuVC.view.removeFromSuperview()
You can add left menu as a subview over application window and slide it using the animation.
Hide/show the status bar if you don't want to show the carrier , time on top of the menu view
class ViewController: UIViewController {
#IBOutlet weak var leading: NSLayoutConstraint!
#IBOutlet weak var sideview: UIView!
var showmenu = false
override func viewDidLoad() {
super.viewDidLoad()
leading.constant = -160
// sideview.layer.shadowOpacity = 5
// sideview.layer.shadowRadius = 5
}
#IBAction func btnmenu(_ sender: UIBarButtonItem) {
if (showmenu)
{
leading.constant = -160
}
else
{
leading.constant = 0
UIView.animate(withDuration: 0.5, animations:{self.view.layoutIfNeeded() })
}
showmenu = !showmenu
}
#IBAction func btntblview(_ sender: UIButton) {
let hk = storyboard?.instantiateViewController(withIdentifier: "TableViewController")as! TableViewController
self.navigationController?.pushViewController(hk, animated: true)
}

Transition from Modal View to Next VC in a TabBar and NavBar

I'm using Swift 2 and xcode 7.1.1.
My app is a tabbar + navigationbar based application.
What I'd like to do:
From my first viewcontroller (CollectionVC) I have a collectionview of images(tabbar at bottom and navbar at top). When you select an image, I transition programmatically to a modalviewcontroller (ImageZoomVC) that allows them to zoom on the image (no tabbar or navbar). From the ImageZoomVC I want to transition programmatically to the UserProfileVC. The UserProfileVC should have the tabbar and navbar like the first view. The navbars back button should also take us back to the ImageZoomVC.
This workflow is similar to facebook. When you select an image, you go to a black screen with just that image and some more info. You can click on anyone tagged in the image and it will push their profile onscreen with the tabbar and navbar back in place.
The Problem:
Once in the ImageZoomVC, I can't transition to the UserProfileVC without losing the tabbar and navbar. I've been able to add a navbar programmatically but there is no back button, and setting a back button hasn't worked. Also, there is no tabbar.
Code:
From my CollectionVC, I transition to the ImageZoomVC from my collectioncell like this:
#IBAction func PhotoButtonPressed(sender: UIButton) {
let imageZoom = ImageZoomVC()
imageZoom.showFrom(self.parentView!)
}
Here is the showFrom function that presents the ImageZoomVC modally. This code is inside the ImageZoomVC:
public func showFrom(viewController: UIViewController) {
//Some stuff here, edited for length
viewController.presentViewController(self, animated: false) {
UIView.animateWithDuration(ImageZoomVC.TransitionAnimationDuration,
delay: 0,
options: [.BeginFromCurrentState, .CurveEaseInOut],
animations: {
[weak self] in
self?.collectionView.alpha = 1
self?.collectionView.transform = CGAffineTransformIdentity
},
completion: {
[weak self] finished in
self?.view.userInteractionEnabled = finished
}
)
}
}
This is the code I'm attempting to use to transition to the UserProfileVC with navbar and tabbar. This doesn't work. It will present the VC, but there is no tabbar or back button.
func userSelected (sender: UIButton) {
let vc = self.presentingViewController?.storyboard?.instantiateViewControllerWithIdentifier("User Profile") as! UserProfileVC
let newNav = UINavigationController(rootViewController: vc)
newNav.navigationBar.barTintColor = UIColor().specialPurple()
newNav.navigationBar.translucent = false
self.presentViewController(newNav, animated: true, completion: nil)
}
A couple notes: The ImageZoomVC doesn't exist in storyboard. It is called and instantiated programmatically.
The ImageZoomVC is based off Agrume from Github found here:
https://github.com/JanGorman/Agrume
I'd like to push the UserProfileVC like facebook does. This current code presents it from the bottom. The code pushViewController is not recognized here in xCode.
Let me know what you think. All thoughts are welcome. Thanks.

Resources