Swapping VC's in a Container View - childVC does not fit Container - ios

Latest Swift/XCode/iOS.
OK, I am trying to get my head around swapping out Child VC's in a Container View. I have read several posts describing how to do it, and they have been very helpful. However, I seem to be having a constraints issue that I can figure out.
I have a Master VC that contains some Container Views. The one Container contains several buttons (acting like a tab bar). When you tap on a button, the view controller in another "Detail" Container changes Child VC's. Code below:
#IBAction func ToBioPage(_ sender: UIButton) {
//SET RIGHT PANE VIEW TO BIO PAGE
//INSTANTIATE NEW VC
let vc = storyboard?.instantiateViewController(withIdentifier: "Biography")
//REMOVE OLD VC
detailPaneVCReference?.willMove(toParentViewController: nil)
detailPaneVCReference?.view.removeFromSuperview()
detailPaneVCReference?.removeFromParentViewController()
//ADD NEW VC
ParentVC?.addChildViewController(vc!)
vc?.view.frame = (detailContainerView?.bounds)!
detailContainerView?.addSubview((vc?.view)!)
//ADD CONSTRAINTS
//TOP ANCHOR
vc?.view.topAnchor.constraint(equalTo: (vc?.view.superview?.topAnchor)!).isActive = true
//BOTTOM ANCHOR
vc?.view.bottomAnchor.constraint(equalTo: (vc?.view.superview?.bottomAnchor)!).isActive = true
//LEADING ANCHOR
vc?.view.leadingAnchor.constraint(equalTo: (vc?.view.superview?.leadingAnchor)!).isActive = true
//TRAILING ANCHOR
vc?.view.trailingAnchor.constraint(equalTo: (vc?.view.superview?.trailingAnchor)!).isActive = true
vc?.didMove(toParentViewController: ParentVC)
}
The VC's of the Detail Container swap out but I cannot get the new one to fit completely. The Child VC runs past the bottom and right sides of the screen. The presence of the constraints added above do not even seem to make a difference. I get the same result whether they are there or not. I was expecting the frame = bounds line of code to ensure that the child fit completely within the Detail Container.
What am I missing/doing wrong?
Edit: Sorry, I forgot to mention that "detailPaneVCReference" is a reference to the starting VC within the Container View, grabbed during the embed segue. "detailContainerView" is a reference to the Container View itself, also grabbed during the embed segue. "ParentVC" is a reference to the MasterVC grabbed in the same fashion.

OK crisis over. Turns out I was designing in storyboard for a 12 inch iPad and running as a 9.7 inch iPad. Several views had fixed value heights/widths - hence the wonky appearance when running the app.

Related

Open same View Controller

Using Xcode 9 / Swift 4, I have a tile application (same as Windows 10 presentation).
When user is on main view controller and click on a tile, I want to open the same view controller and set parentId, in order to show child tiles.
App can have infinite number of child of child.
But, app crash when I try to push same View Controller as current displayed:
let vc = currentStoryboard.instantiateViewController(withIdentifier: "TileViewController") as! TileViewController
vc.parentId = id
vc.title = item.name
currentViewController.navigationController?.pushViewController(vc, animated:true)
The exception your are having its not related of pushing the same instance another time. Well you are probably adding some constraints programmatically, And also its being added in viewDidLoad/viewWillAppear/viewDidAppear because thats what can i understand from the exception that your getting:
Impossible to set up layout with view hierarchy unprepared for constraint.
If its so then you'll need to add it in either updateViewConstraints() which is called when the view controller's view needs to update its constraints, or inside viewWillLayoutSubviews().

iOS : Swift : Right and Left view controller transitions between mutiple view controllers

I have close to 8 view controllers , Each and every view controller has next and back button . How could I do left and right transitions here through swift code . To be more specific on tapping back , previous view controller should slide from left and on tapping next , the next view controller should slide from right.
I am pretty new to iOS development , Any help would be really appreciable.
Thanks In Advance
You should be able to do it using UIPageViewController combining it with its delegate.
However, I'm gonna shamelessly point you to my open source project of custom container with interactive transitions - InteractiveTransitioningContainer. While it aims at allowing to implement an interactive container (as an example it includes a container that allows swiping through viewControllers the way as UIPageViewController works), you can use the SwipeToSlideInteractiveTransitioningContainer class to achieve what you want:
// here you will want your 8 controllers
let vcs = [FirstViewController(), SecondViewController(), ThirdViewController()]
let container = SwipeToSlideInteractiveTransitioningContainer(with: vcs)
// this will disable swiping to navigate between containees
container.interactive = false
self.present(container, animated: true, completion: nil)
// shows the second viewController (index based from 0)
container.show(at: 1, animated: true)
// or move using previous and next convenience methods
let success = container.showNext(animated: true)
You can install it using Cocoa pods. Any feedback welcome :).

Detached Controller Issues on a Dynamically Loaded UIStackView

I am getting a "Presenting view controllers on detached view controllers is discouraged" warning in a somewhat specialized architecture. And - there are some fairly big UI issues resulting from it. I have an architecture with 2 distinct unconnected groups in my storyboard. The first group is the main interface of my app and includes an UIStackView. The second group consists of an UIView plus attached popover segue as shown in the image below.
I dynamically populate the UIStackView of group 1 with up to 8 instances of the UIView of group 2. This is done in a function called loadViews() in the UIStackView subclass which is called as needed. Here is the cleaned up pseudo code for illustration:
for i in 0 ..< green.count {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let greenVC = storyboard.instantiateViewControllerWithIdentifier("greenViewController") as! GreenVC
greenVC.progressionStackView = self
greenVC.index = i;
greenViewControllers.append(greenVC)
if let greenView = greenVC.view as! GreenView! {
greenView.fillColor = UIColor.orangeColor()
greenView.setNeedsDisplay()
self.addArrangedSubview(greenView)
}
}
self.layoutIfNeeded()
Every time I trigger the popover on one of the embedded green views in the stack view I get the warning from above. More importantly, when running on an iPad in split view mode, the stack view loses a green view each time until there are none left. The latter is just a display issue, because on refresh all views are back.
I am completely stumped and am not sure how to fix this or implement things differently. If the issue is that the loaded views are not attached, can they be "re-attached"? Or is there a way to dynamically load a stack view with up to 256 views that are attached to it?
Solved:
Another lesson in taking Xcode warnings to heart - even if the word discouraged is used. As in this case, things tend to break. The solution was obvious in hindsight. The new view controllers that were instantiated as greenVC had to be attached to the containing view controller - i.e. the one several layers up in the view hierarchy that contains this UIStackView:
vcContainingStackView.addChildViewController(greenVC)
The line above is called right before appending greenVC to my array of added view controllers. Of course now removeFromParentViewController() has to be called as well where instances of GreenVC get removed, but otherwise that's it. The warning is gone and so is the issue of vanishing views.

Assigning two views to a single Container View using swift in iOS 8

I am trying to assign two view controllers to a Container View using the Interface Builder. I tried to do so, but whenever I try to "embed" the second view controller to my Container View, instead of adding another VC to it, it just replaces the one that was embedded already.
Ultimately, my main goal is to have a screen that has the following elements (in order, from top to bottom):
-A navigation bar
-A view of height 50 that contains a segmented controller (which will switch between tableVCs)
-A main view, which will contain my Container view
-A tabbed bar
My current setup is almost as described above. Here is a picture:
The view controller I am interested in the most is in the one with the highlighted container(HomeViewController). The approach I am currently using is hacky, because I currently have 2 container views, one on top of another, and they embed the 2 table view controllers depicted to the right (one per container).
I do not like this approach very much because both containers get instantiated whenever the main VC (Home View Controller) is instantiated, therefore making 2 network calls by default to load their content, possibly slowing down the device and maybe using more memory than needed.
Ideally, I would load the content of one table view controller that is mapped to one of the segmented controls. Then, I would have a mechanism that somehow instantiates the second table view controller whenever I go to the second button in the segmented control (and possibly deallocating/getting rid of the other VCs), and so on with the third. Or somehow be able to display/alternate between 2 or more view controllers in an area (view) inside my HomeViewController.
Currently I have this simple code that switches (hides and shows) between container views in my HomeViewController:
#IBAction func segmentChanged(sender: AnyObject) {
switch segmentedControl.selectedSegmentIndex{
case 0:
println("index1 selected")
containerView1.hidden = false
containerView2.hidden = true
break
case 1:
println("index2 selected")
containerView1.hidden = true
containerView2.hidden = false
break
default:
containerView1.hidden = false
containerView2.hidden = true
break
}
}
As I said, this only switches between the views that are loaded already in my view controller, with the data in them already.
I just wanted to see if what I am trying to code is doable, or if I am actually tackling the problem the right way, although I doubt I am doing so.
Thank you for reading my post and for your advice in advance.
Cheers!
Add embed segue to NavigationController, add ViewController as rootViewController to NavigationController, from rootViewController add as many segue as you wish. To load controller you need just override segue class to push without navigation.
class NoAnimationSegue: UIStoryboardSegue {
override func perform() {
self.sourceViewController.navigationController?.pushViewController(self.destinationViewController, animated: false)
}
}

UIView frame coming as zero (0 0; 0 0) when view appears second time

I am using navigation controller (UINavigationController) for my iOS app and am using Storyboard.
I've several UIViews (that act as subViews) in my view controller (VC) and I have set outlet for those UIViews in Xcode.
My first VC in my navigation acts as a kind of Home (main page for the app).
All subViews of my second VC get displayed properly when second VC appears for the first time.
But if I go to Home (or first VC) and come back to second VC then my subViews there don't display.
I've put a breakpoint in viewWillAppear method of second VC and below is frame description for one of the views.
First time: frame = (20 20; 280 150)
Go to Home VC and come to VC Second time: frame = (0 0; 0 0)
Can you please guide me how to debug this issue? Please let me know if any other info is required. Thanks.
When a view controller appears misaligned or some of the sub views seems missing when it loads second time then it means that something (am not able to figure out this) is breaking your layout (or something has changed your view's size during execution). So you set frames (by using frame property) of UIViews in viewWillAppear method and it will work fine.
Thanks #mital and #xlc for the hint.

Resources