Adding View Controllers side by side into a Scroll View - ios

How can i add my existing View Controllers into a Scroll View. I have tried the code below inside 'viewDidLoad' but it didn't work. Thanks
let view1 = ViewController6()
let view2 = ViewController2()
let view3 = ViewController3()
contentView.addSubview(view1)
contentView.addSubview(view2)
contentView.addSubview(view3)
self.contentView.contentSize = CGSize(width: self.view.frame.width * 3, height: self.view.frame.height)

Check this code Here I am doing the exactly thing that you want to achieve.
func setupScrollView()
{
//loop for
for i in 0..<3 {
//we instantiate our viewController from storyboard
let news2 = self.storyboard?.instantiateViewController(withIdentifier: "NewsMasterViewController") as! NewsMasterViewController
//we adjust the frame according
news2.view.frame = CGRect(x: CGFloat(i) * self.scrollView.frame.size.width + CGFloat(MasterViewController.margin), y: 0, width: self.scrollView.frame.size.width - CGFloat(MasterViewController.margin * 2), height: self.scrollView.frame.size.height)
//we call layoutSubviews for constraints adjustments
news2.view.layoutSubviews()
self.addChildViewController(news2)
//added the view of my viewController "news2" to scrollView
self.scrollView.addSubview(news2.view)
news2.didMove(toParentViewController: self)
//added the viewController "news2" to my array of viewControllers
newsMasterViewControllers.append(news2)
}
//adjusted contentSize of scrollView according the number of viewControllers added
self.scrollView.contentSize = CGSize(width: self.view.frame.size.width * 3, height: self.scrollView.frame.size.height);
}
I hope this helps you

Related

UIViewController hidden behind UINavigationController but should be placed below

I'm working on a app where I've got a NavigationBar at the top and added a UIViewController as an RootViewController.
Now my plan was to add a new Subview to this UIViewController. The new Subview extended also of UIViewController. I added de view (Gray Rect) of the controller to the UIViewController but it is placed behind the NavigationBar. I don't want that.. So I searched for a solution and found something interesting..:
When I just add a UIView() (Green Rect) to the UIViewController, the placing of the view works perfectly, as I would love see it from the other UIViewController-View.
My code looks like following:
class DashboardController: UIViewController {
var ccview:ContactCircleController!
override func viewDidLoad() {
super.viewDidLoad()
edgesForExtendedLayout = []
self.view.backgroundColor = .white
let test = UIView()
test.backgroundColor = .green
test.frame = CGRect(x: self.view.frame.width - 200, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
self.view.addSubview(test)
setup()
}
func setup(){
ccview = ContactCircleController()
ccview.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
ccview.edgesForExtendedLayout = UIRectEdge.top
self.view.addSubview(ccview.view)
}}
I've already unchecked the "Extend Edges" - toggle of the navigationcontroller on the storyboard. I also added edgesForExtendedLayout = [] to the UIViewController and for the UIView it worked fine. But for the view of another UIViewController... it didn't worked.
Thank you!
If you use Debug View Hierarchy, you will see that your gray ccview.view is not behind the navigation bar, but rather it is not keeping the height of self.view.frame.width / 2.
This is because the .view of a UIViewController instantiated from Storyboard has by default an .autoresizingMask = [], whereas the .view of a UIViewController instantiated without a storyboard has a default .autoresizingMask = [.flexibleWidth, .flexibleHeight].
You can correct this by changing setup() to:
func setup(){
ccview = ContactCircleController()
ccview.view.frame = CGRect(x: 0, y: 0, width: self.view.frame.width / 2, height: self.view.frame.width / 2)
// remove this line
//ccview.edgesForExtendedLayout = UIRectEdge.top
// add this line
ccview.view.autoresizingMask = []
self.view.addSubview(ccview.view)
}

Xcode, Swift: How to center popover box

Link to my github account with files, simply download zip: https://github.com/jzhang172/modalTest
When I click on the "popover" link, I would like to center the popover in the center of the screen.
I tried referencing some stackoverflow questions such as:
how to center a popoverview in swift
but no luck. I'm a noob in swift and I'm only using swift, not objective C.
Screenshot of what I see:
Replacing
controller?.sourceRect = CGRectMake(0.0, self.view.layer.bounds.height * 0.5,0.0,0.0)
with
controller?.sourceRect = CGRectMake(self.view.layer.bounds.width * 0.5, self.view.layer.bounds.height * 0.5,0.0,0.0)
will center the popover content horizontally and vertically.
You can center the UIPopover in your view with the code below.
let controller = vc.popoverPresentationController
controller?.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
controller?.sourceView = self.view
controller?.sourceRect = CGRectMake(0.0, self.view.layer.bounds.height * 0.5,0.0,0.0)
vc.preferredContentSize=CGSize(width: 400, height: 200)
Swift 3:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let popoverPresentationController = segue.destination.popoverPresentationController {
let controller = popoverPresentationController
controller.permittedArrowDirections = UIPopoverArrowDirection(rawValue: 0)
controller.sourceView = self.view
controller.sourceRect = CGRect(x: UIScreen.main.bounds.width * 0.5 - 200, y: UIScreen.main.bounds.height * 0.5 - 100, width: 400, height: 200)
segue.destination.preferredContentSize=CGSize(width: 400, height: 200)
}
}

How to embed stack view in scroll view programmatically

I have tried embedding it, but my stack view is dynamic and my app is also changing orientations time to time. I have segment control at the end of the view.
I have also tried googling it but had no luck. thanks in advance.
So far I have done:
In view did load:
mainStackView.axis = UILayoutConstraintAxis.Vertical
mainStackView.spacing = 3
scrollView.frame = self.view.bounds
scrollView.addSubview(mainStackView)
view.addSubview(scrollView)
In view did layout:
override func viewDidLayoutSubviews()
{
super.viewDidLayoutSubviews()
let top = topLayoutGuide.length
let bottom = bottomLayoutGuide.length
self.mainStackView.frame = CGRect(x: 0, y: top, width: view.frame.width, height: view.frame.height - top - bottom).insetBy(dx: 10, dy: 10)
dispatch_async(dispatch_get_main_queue())
{
self.scrollView.frame = self.view.bounds
self.scrollView.contentSize = CGSize(width: self.view.bounds.width, height: self.segmentedControl.frame.origin.y + self.segmentedControl.frame.height + 50)
}
print(scrollView.contentSize)
}
You need to set the height constraint of segment control.
For Example:
segmentedControl.heightAnchor.constraintEqualToConstant(50).active = true
More over, you can Add Empty bottom view to avoid stack view's must fill mechanism. This will show you desired view output.
var bottomView = UIView(frame: CGRectZero)
stackView.addArrangedSubview(bottomView)

When to use UITouch vs UIScroll

I would like to achieve the design you see in dating apps. Where you can vertically scroll images of a profile and also horizontally scroll to view the next or previous person in the list.
Currently I have my views laid out as such.
Previous-UIView - current UIView - next UIView
UIScrollView. UIScrollView. UIScrollView
Images. Images. Images
UIView. UIView. UIView
Profile info. Profile info. Profile info
UIPageControl. UIPageControl UIPageControl.
Only one of the Views occupies the main view with next and previous off screen. Ideally when the user moves the view left I would programmatically remove the previous view, make current the previous, the next current and add a new view for next. Visa versa for moving right.
What is the best way to scroll the views horizontally?
Should I wrap them all in a UIScrollView? And would that interfere with the UIScrollView sub Views?
Or should I program touch controls to move the views?
Or is there a better way?
I'm still a newbie at iOS development so any help would be greatly appreciated.
So I've tried some experimenting with a test app and I'm pleased to say you can have UIScrollviews inside UIScrollviews.
I was able to get it running perfectly. Here is my code below.
override func viewDidLoad() {
super.viewDidLoad()
self.superView.delegate = self
// Do any additional setup after loading the view, typically from a nib.
var subImages1 = ["IMG_0004.JPG","IMG_0005.JPG","IMG_0008.JPG"]
var subImages2 = ["IMG_0009.JPG","IMG_0010.JPG","IMG_0011.JPG"]
var subImages3 = ["IMG_0013.JPG","IMG_0017.JPG","IMG_0018.JPG"]
self.images.append(subImages1)
self.images.append(subImages2)
self.images.append(subImages3)
self.superView.frame = self.view.frame
self.superView.contentSize = CGSizeMake(self.view.frame.width*3, self.view.frame.height)
self.superView.contentOffset = CGPoint(x:self.view.frame.width,y:0)
self.superView.pagingEnabled = true
self.view.addSubview(self.superView)
//layout the UIVeiws into the master ScrollView
for i in 0...2{
var offset = self.view.frame.width * CGFloat(i)
var pView = UIView()
pView.frame = CGRectMake(offset, 0, self.view.frame.width, self.view.frame.height)
pView.backgroundColor = colours[i]
self.superView.addSubview(pView)
self.profileViews.append(pView)
}
// Add sub Scroll views and images to the Views.
for (index, view) in enumerate(self.profileViews){
var scrollView = UIScrollView()
scrollView.delegate = self
scrollView.frame = CGRectMake(10, 10, self.view.frame.width-20, self.view.frame.height-20)
scrollView.pagingEnabled = true
scrollView.contentSize = CGSizeMake(scrollView.frame.width, scrollView.frame.height * CGFloat(images[index].count))
for (index2, image) in enumerate(images[index]){
var subImage = UIImageView()
subImage.frame = CGRectMake(0, scrollView.frame.height * CGFloat(index2), scrollView.frame.width, scrollView.frame.height)
subImage.contentMode = UIViewContentMode.ScaleAspectFit
subImage.image = UIImage(named: image as! String)
scrollView.addSubview(subImage)
}
view.addSubview(scrollView)
self.scrollViews.append(scrollView)
}
}
//Use the did end decelerating as it executes the code once the scoll has finished moving.
func scrollViewDidEndDecelerating(scrollView: UIScrollView) {
if(scrollView == self.superView){
var contentOffset = scrollView.contentOffset
var pageWidth = self.superView.frame.width
var fractionalPage:Double = Double(self.superView.contentOffset.x / pageWidth)
var page = lround(fractionalPage)
// In this example I take the last UIView from the stack and move it to the first.
// I would do the same in the real app but update the contents of the view after
if(page == 0){
var tempView = self.profileViews[2]
self.profileViews[2].removeFromSuperview()
self.profileViews.removeAtIndex(2)
for view in self.profileViews{
view.frame = CGRectMake(view.frame.minX + self.view.frame.width, 0, view.frame.width, view.frame.height)
println(view.frame)
}
tempView.frame = CGRectMake(0, 0, tempView.frame.width, tempView.frame.height)
self.profileViews.insert(tempView, atIndex: 0)
self.superView.addSubview(tempView)
var newOffset = contentOffset.x + pageWidth
self.superView.contentOffset = CGPoint(x: newOffset, y: 0)
}
// Take the first view and move it to the last.
if(page == 2){
var tempView = self.profileViews[0]
self.profileViews[0].removeFromSuperview()
self.profileViews.removeAtIndex(0)
for view in self.profileViews{
view.frame = CGRectMake(view.frame.minX - self.view.frame.width, 0, view.frame.width, view.frame.height)
println(view.frame)
}
tempView.frame = CGRectMake(tempView.frame.width*2, 0, tempView.frame.width, tempView.frame.height)
self.profileViews.append(tempView)
self.superView.addSubview(tempView)
var newOffset = contentOffset.x - pageWidth
self.superView.contentOffset = CGPoint(x: newOffset, y: 0)
}
}
}

How do I change UIView Size?

I have trouble with modifying my UIView height at launch.
I have to UIView and I want one to be screen size * 70 and the other to fill the gap.
here is what I have
#IBOutlet weak var questionFrame: UIView!
#IBOutlet weak var answerFrame: UIView!
let screenSize:CGRect = UIScreen.mainScreen().bounds
and
questionFrame.frame.size.height = screenSize.height * 0.70
answerFrame.frame.size.height = screenSize.height * 0.30
It has no effect on the app during run time.
I use autolayout but I only have margins constraints...
Am I doing it all wrong?
This can be achieved in various methods in Swift 3.0 Worked on Latest version MAY- 2019
Directly assign the Height & Width values for a view:
userView.frame.size.height = 0
userView.frame.size.width = 10
Assign the CGRect for the Frame
userView.frame = CGRect(x:0, y: 0, width:0, height:0)
Method Details:
CGRect(x: point of X, y: point of Y, width: Width of View, height:
Height of View)
Using an Extension method for CGRECT
Add following extension code in any swift file,
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
Use the following code anywhere in your application for the view to set the size parameters
userView.frame = CGRect(1, 1, 20, 45)
Here you go. this should work.
questionFrame.frame = CGRectMake(0 , 0, self.view.frame.width, self.view.frame.height * 0.7)
answerFrame.frame = CGRectMake(0 , self.view.frame.height * 0.7, self.view.frame.width, self.view.frame.height * 0.3)
Swift 3 and Swift 4:
myView.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
Hi create this extends if you want. Update 2021 Swift 5
Create File Extends.Swift and add this code (add import foundation where you want change height)
extension UIView {
var x: CGFloat {
get {
self.frame.origin.x
}
set {
self.frame.origin.x = newValue
}
}
var y: CGFloat {
get {
self.frame.origin.y
}
set {
self.frame.origin.y = newValue
}
}
var height: CGFloat {
get {
self.frame.size.height
}
set {
self.frame.size.height = newValue
}
}
var width: CGFloat {
get {
self.frame.size.width
}
set {
self.frame.size.width = newValue
}
}
}
For Use (inherits Of UIView)
inheritsOfUIView.height = 100
button.height = 100
print(view.height)
For a progress bar kind of thing, in Swift 4
I follow these steps:
I create a UIView outlet : #IBOutlet var progressBar: UIView!
Then a property to increase its width value after a user action var progressBarWidth: Int = your value
Then for the increase/decrease of the progress progressBar.frame.size.width = CGFloat(progressBarWidth)
And finally in the IBACtion method I add progressBarWidth += your value for auto increase the width every time user touches a button.
You can do this in Interface Builder:
1) Control-drag from a frame view (e.g. questionFrame) to main View, in the pop-up select "Equal heights".
2)Then go to size inspector of the frame, click edit "Equal height to Superview" constraint, set the multiplier to 0.7 and hit return.
You'll see that constraint has changed from "Equal height to..." to "Proportional height to...".
Assigning questionFrame.frame.size.height= screenSize.height * 0.30 will not reflect anything in the view. because it is a get-only property. If you want to change the frame of questionFrame you can use the below code.
questionFrame.frame = CGRect(x: 0, y: 0, width: 0, height: screenSize.height * 0.70)
I know that there is already a solution to this question, but I found an alternative to this issue and maybe it could help someone.
I was having trouble with setting the frame of my sub view because certain values were referring to its position within the main view. So if you don't want to update your frame by changing the whole frame via CGRect, you can simply change a value of the frame and then update it.
// keep reference to you frames
var questionView = questionFrame.frame
var answerView = answerFrame.frame
// update the values of the copy
questionView.size.height = CGFloat(screenSize.height * 0.70)
answerView.size.height = CGFloat(screenSize.height * 0.30)
// set the frames to the new frames
questionFrame.frame = questionView
answerFrame.frame = answerView

Resources