Load UIViewcontroller into a scrollView smaller than screen? - ios

My scrollView size is smaller than the screen size in height (80% of height).
I would like to load into it a few UIViewControllers.
Later, when I try to use the view.height of that viewController, it still has the size of a full screen and not the size of the scroller.
I would like to be able to load this controller into my scroller and make it the size of that scroller, so view.height will be 80% of screen, and not the original controller height, so I can position things in the right way.
EDIT:
controller1 = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
var frm = view.frame
frm.origin.x=CGFloat(count)*view.frame.width
frm.origin.y=0
frm.size.height=scrollView.frame.height
controller1.view.frame=frm
scrollView.addSubview(controller1.view)

You can only achieve this by using below concept.
Let your UIScrollView is in MainVC. Now here you wanted to add few UIViewControllers.
If you wanted to this from storyboard
Take a containerView
give it autolayout
assign the required UIViewController.
reference - https://spin.atomicobject.com/2015/07/21/ios-container-views/
If you wanted to this by code
Create a child VC
add it in your MainVC
give the frame as per your requirement.
reference - https://github.com/codepath/ios_guides/wiki/Adding-and-Removing-Child-View-Controllers
Description
In both the case actually you making the MainVC as a parentVC and then creating its childs. Whenever your MainVC is loaded is loads your child VC also can set the frame of childVC as per your requirment.
To pass the data from Parent to child, you can directly do this by assigning variables. But while passing the data from Child to parent you need to use protocol-delegate or NSNotification.
Still something unclear then ask.

Related

Swift - Present a UIView (not a ViewController)

I have two UIViewControllers and I would like to .present the gray UIView like you would usually present a ViewController (appearing bottom up and user can slide down to dismiss).
Screenshots for a better understanding:
The bottomBar is a ContainerView and should not change by switching between the VC's, only the gray UIView which you can see in the 2nd picture.
I know I could just .present ViewControllerB without an animation and then just let the UIView appear from out of the screen. But if I do it like this the user is not able to drag down the UIView to dismiss it.
This is how I present ViewControllerB ("wishlistViewController) at the moment.
let wishlistViewController = self.storyboard?.instantiateViewController(withIdentifier: "WishlistVC") as! WishlistViewController
wishlistViewController.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
self.navigationController?.present(wishlistViewController, animated: false)
}
Main Problem is that my UIView is not fullscreen. Otherwise I could just .present ViewControllerB. However, with my design the background image would be animated by .presenting or .dismissing as well and I do not want that.
There is probably a very easy solution for this but I couldn't find on presenting ONLY a UIView.
Grateful for any tips :)
Well, there are two answers I can think of:
1) If you want, you could just animate it in from the bottom using UIView.animate() on a y-position constraint it has, or on its layer's y-position attribute. You could then attach a UISwipeGestureRecognizer to it so that if you swipe down on it, it will animate back down.
2) Make your views that you'd like to present viewControllers and have them be presented with a custom modal animation. This sounds like more work than you wanna do though. Here's a cool tutorial on youtube that walks you through how to create a custom animation transition between 2 view controllers:
https://www.youtube.com/watch?v=B9sH_VxPPo4
However, as far as I know, those .dismiss and .present methods are only meant for view controllers. Hopefully one of the two options I gave were helpful!

Adding An UITableViewController on to a SubView

An UITableViewController pretty much takes up the entire view. I need a way to limit its height, width and add some shadows etc. For a clear explanation, I won't show the UITableViewController's contents.
Without the use of a storyboard, I subviewed the UITableViewController:
// In another UIViewController
let otherController = OtherController() // A subclass of UITableViewController
let otherControllerView = otherController.view
someView.addSubView(otherControllerView)
[...] // bunch of constraints
Notes:
In AppDelegate, if I set the rootController as OtherController(), everything works as it should. If I change it back to SomeView(), I see my modified tableView. If I should click it, it disappears.
This was the only thing that came close to my issue but sadly, I could not understand the answers provided as nothing made any sense to me.
I need to understand, why it disappears when touched etc.
view.bringSubviewToFront(...) proved futile. I'm gessing that a tableView should be rendered in its own controller and not in another view?
So just to answer this question, indeed you got two options. One is the best way, as suggested by Rakesha. Just use UITableView. Add it as a subview. Done.
And in the future, if you really want any controller to be added onto any UIView, remember you need to add that controller as a child. For example, in your case:
The controller of the view that will hold your UITableViewController will add such UITableViewController as a child.
self.addChild(yourUITableViewController)
self.whatEverViewContainer.addSubview(yourUITableViewController.view)
// Take note of the view of your tableViewController above^.
// Then setup the constraints of your yourUITableViewController.view below.
I hope this helps!
You must add the instance of UITableViewController's subclass as child view controller of the other view controller. You need to ensure few points in order to make it work. The points are as listed below:
Create the instance of your TableViewController
Add it as a child view controller of the other view controller
Add its view as a subview of the desired view (you may do these steps in viewDidLaod since they need to be done only once)
Keeping in mind the view cycle of a view controller. You must keep a weak reference of the child view controller aka TableViewController to adjust its view frame after the parent view controller has laid its subviews.
Code here:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let vc = TableViewController()
addChildViewController(vc)
view.addSubview(vc.view)
vc.didMove(toParentViewController: self)
childVC = vc
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
childVC?.view.frame = view.frame
}

Changing width of child view controller

I added child view controller to parent view controller programmatically in swift 3.0.
But I do not want the child view controller width as full screen, I want to customise the width and height of the child view controller. I tried to open the custom size child view controller, but it is not working.
// Here is my code
let secondViewController = storyboard.instantiateViewController(withIdentifier: storyBoardName)
secondViewController.modalPresentationStyle = UIModalPresentationStyle.custom
secondViewController.view.frame = CGRect(x: 0, y: 0, width: self.view.bounds.width-500, height: self.view.bounds.height)
self.present(secondViewController, animated: false, completion: nil)
Is there a way to achieve this?
In your code, you are not adding the secondViewController as childview controller. You are presenting that view controller. There is a difference.
You are trying to use UIModalPresentationStyle.custom to present viewcontroller using custom style. But using this custom style is not this trivial.
From documentation:
Creating a custom style involves
subclassing UIPresentationController and using its methods to animate
any custom view onto the screen and to set the size and position of
the presented view controller. The presentation controller also
handles any adaptations that occur because of changes to the presented
view controller’s traits
It tells you that you need to subclass UIPresentationController and subclass its method(with other methods) - (CGRect)frameOfPresentedViewInContainerView to set the frame of the presented viewcontroller.
More is explained in this link.
You can ofcourse achieve all this by actually adding a childviewcontroller.
Steps would be like this:
Create your child viewcontroller instance.
Set its view frame to whatever you want.
Add its view as a subview on to parent view controller's view using addSubview:
Call [addChildViewController] on parent viewcontrller (https://developer.apple.com/documentation/uikit/uiviewcontroller/1621394-addchildviewcontroller)
It depends on what you're trying to do, when I want to show some UI on top of another UIViewController I usually use a fullscreen view controller with self.modalPresentationStyle = .overFullScreen. Then I create another view which has the visible size I actually want to show to the user. This allows you to do pretty much anything you want.
But if you want an actual child viewcontroller, you need to use the appropriate functions for it.

How can i make 1 viewcontroller slide up from bottom

I have 2 viewcontrollers.The first one should occupy major portion of the screen and second one should be at the bottom portion
How do i make the bottom viewcontroller slide up to occupy the entire screen
you can use addchildViewController method of UIViewController
basically when you want to show the other VC. do this in first
let vc = SecondVC()
self.addChildViewController(vc)
self.view.addSubView(vc.view)
//now set constraints or set the vc.view frame to whatever position you want

adding a uipageviewcontroller to a uistackview

I'm trying to add a sliding photo gallery functionality to the top portion of a view.
To give context, a user taps on a button or row or something. Then i load a scrollview with a uistackview in it. organized vertically, i had an image, and then another stack view with some text in it. Now, i want that image to become part of a larger "gallery". My research told me to implement UIPageviewcontroller and add the other images to a childVC.
i used this as a tutorial (the first example): http://www.raywenderlich.com/76436/use-uiscrollview-scroll-zoom-content-swift
the only relevant deviation from the tutorial my app has is that it creates things programmatically.
With my proof of concept for the gallery functionality, i wanted to integrate it with the previously mentioned stack view. my plan was to first add the pageviewcontroller stuff into the overall stack view with the original image view right below it and then simply remove the original image view to leave me the final product.
i was able to add the pageviewcontroller.view to the stackview, but the gallery doesn't show. taking a look at the UI Inspector, i can see that the gallery is kinda loaded, but it's messed up.
it's as if the uiview has a frame of 0 height and so the other stack view items don't respect the images that the pageviewcontroller is trying to show.
I think it could be that stack views can only handle specific views, not stuff as complicated as pageviewcontrollers.
also note: my implementation is all programmatic, no storyboards, and so for no xibs. so maybe i missed something here.
here is some code, if it helps:
note the constrain functions you see are from the "cartography" pod
this adds the "gallery" to the stack view, it's a delegate function from my view
func addZoomStuff(sender: UIStackView) {
let zoomer = PageBaseViewController()
addChildViewController(zoomer)
zoomer.view.translatesAutoresizingMaskIntoConstraints = false
zoomer.view.tag = 5
sender.addArrangedSubview(zoomer.view)
zoomer.didMoveToParentViewController(self)
}
this is what creates the scrollview, image view, etc for the gallery items:
override func viewDidLoad() {
super.viewDidLoad()
//MARK: - Zoom View Elements
// prep
scrollView = UIScrollView(frame: self.view.frame)
scrollView.delegate = self
self.view.addSubview(scrollView)
constrain(scrollView, view) { view, view2 in
view.edges == view2.edges
}
self.view.setNeedsUpdateConstraints()
// 1
let image = UIImage(named: imageName)!
imageView = UIImageView(image: image)
// 2
scrollView.addSubview(imageView)
constrain(imageView){ view in
view.edges == view.superview!.edges
}
scrollView.contentSize = image.size
i tried adding the constraints like this but there was no effect
func addZoomStuff(sender: UIStackView) {
let zoomer = PageBaseViewController()
addChildViewController(zoomer)
view.addSubview(zoomer.view)
constrain(zoomer.view, view) { view, view2 in
view.width == view2.width
view.height == view2.height * 2 / 3
view.leading == view2.leading
view.top == view2.top
}
zoomer.view.setNeedsUpdateConstraints()
zoomer.view.removeFromSuperview()
zoomer.view.translatesAutoresizingMaskIntoConstraints = false
zoomer.view.tag = 5
print("sender.subviews: \(sender.subviews)")
sender.addArrangedSubview(zoomer.view)
zoomer.didMoveToParentViewController(self)
print("sender.subviews: \(sender.subviews)")
}
if this method isn't going to work, can i do a nested horizontal stack view instead of the pageviewcontroller and somehow get that same scrolling/snap effect to see on image view at a time?
TLDR;
Create a subclass of UIPageViewController, make it it's own delegate.
Initialize the subclass with a plain UIViewController, only set a backgroundcolor.
In the pageviewcontroller subclass, implement the two delegate callbacks for a next and previous viewcontroller: create a plain viewcontrolller, with some random backgroundcolor.
If this works, replace the plain viewcontroller by your actual contentviewcontroller.
Long version:
Have you seen this: Maybe this link will help: https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/PageViewControllers.html
It might help, as it explains the details of UIPageViewController. Basically, you need to create a viewController (not a view!), that shows one page of the gallery. So this VC has a stackview, and manages the content of it. The pageviewcontroller is initialized with your first contentviewController. If you create a subclass of the uipageviewcontroller, you can set self of that subclass as the delegate of it. Implement the delegate callbacks that return the next or previous viewController and thats it. For this last part, it is convenient to have a property on the contentviewcontroller from which the subclasses of the pageviewcontroller can figure out what data to set on the next or previousviewcontroller.
Your title seeks to hint at some confusion: its not possible to add a viewcontroller to a view. You can only add other views to a (stack)view. A viewcontroller owns and manages a viewhierarchy. A pageviewcontroller has no content, but manages the insertion and removal of viewcontrollers. as the pageviewcontroller is a containerviewcontroller, it will als take the contentViewcontrollers' views and place them in the viewhierarchy. But this is not something your code has to do when you subclass UIPageViewControlller and implement it's delegates on itself (and don't forget to assign self to be the delegate).

Resources