0
votes

I want to create a simple view hierarchy in a Swift project that has a UIScrollView which should act as an expandable container to the subviews which are: UILabel, UITextView and a Button.

The catch here is that I am doing it all programmatically using visual format language and cannot do it in Interface Builder. My code below displays a scrollview, however it cannot scroll down to show the views which are below it and the views themselves are not sized correctly. It is static. Also the subviews are not expanding to fill up the screen.

I want to display a scrollview which is fullscreen size and also its subviews fill the screen horizontally with varying heights depending on what size I set. They currently only are around 200pt wide which is unusual.

viewDidLoad() {
  view.addSubview(scrollView)

  //This function is a convenience function which applies constraints 
  view.addConstraints(withFormat: "H:|[v0]|", toViews: scrollView)
  view.addConstraints(withFormat: "V:|[v0]|", toViews: scrollView)

  //Here I add the 3 subviews mentioned above
  scrollView.addSubview(nativeText)
  scrollView.addSubview(mnemonicDescription)
  scrollView.addSubview(addButton)

  //Here I apply constraints using format language
   scrollView.addConstraints(withFormat: "H:|[v0]|", toViews: foreignText)

// Note that this should make foreignText expand the full width. It doesn't, its very small

//I continue to add subviews with horizontal and vertical constraints however they do not fill the container view as expected.
}
2
try specifying content size of scrollviewDarshan Karekar
Hey Darsha, if you mean adding something like scrollView.contentSize = CGSize(width: view.frame.width, height: view.frame.height) then it does not in fact work. It simply makes the scrollview the size of the screen, but I cannot scroll past the size of the scrollview for other views which are underneath what is being displayed. It is still static. ThanksM3nd3z
is it working when you give static height?Darshan Karekar
By setting the content size above I believe that makes it have a static height and width? This does make the scrollview the fullsize of the view, however the scrollview wont scroll and the subviews are the wrong width (no spanning the full screen)M3nd3z
Best to use Auto-Layout and Constraints, not frames and contentSize. I have an example here using several different methods of constraints, including VFL: github.com/DonMag/SWAutoLayoutScrollViewDonMag

2 Answers

1
votes

Here is a (fairly) simple example of adding 3 views to a Scroll View and using VFL to set the constraints.

override func viewDidLoad() {
    super.viewDidLoad()

    // create a scroll view with gray background (so we can see it)
    let theScrollView = UIScrollView()
    theScrollView.backgroundColor = .gray

    // add it to the view
    view.addSubview(theScrollView)

    // add constraints so the scroll view fills the view
    view.addConstraintsWithFormat("H:|[v0]|", views: theScrollView)
    view.addConstraintsWithFormat("V:|[v0]|", views: theScrollView)

    // create three UIViews - nativeText (red), mnemonicDescription (green), addButton (blue)

    let nativeText = UIView()
    nativeText.translatesAutoresizingMaskIntoConstraints = false
    nativeText.backgroundColor = .red

    let mnemonicDescription = UIView()
    mnemonicDescription.translatesAutoresizingMaskIntoConstraints = false
    mnemonicDescription.backgroundColor = .green

    let addButton = UIView()
    addButton.translatesAutoresizingMaskIntoConstraints = false
    addButton.backgroundColor = .blue

    // add those three views to the scroll view
    theScrollView.addSubview(nativeText)
    theScrollView.addSubview(mnemonicDescription)
    theScrollView.addSubview(addButton)

    // set horizontal / width constraints for the three views so they fill the scroll view
    // "H:|[v0(==v1)]|" means "make the width of v0 equal to the width of v1, and pin to leading and trailing"
    theScrollView.addConstraintsWithFormat("H:|[v0(==v1)]|", views: nativeText, theScrollView)
    theScrollView.addConstraintsWithFormat("H:|[v0(==v1)]|", views: mnemonicDescription, theScrollView)
    theScrollView.addConstraintsWithFormat("H:|[v0(==v1)]|", views: addButton, theScrollView)

    // set the vertical / height constraints of the three views
    // (==200) means "set the height to 200"
    // "|" means "pin to edge"
    // "-40-" means 40 points of space

    // so the following 3 lines will put:

    //      nativeText (Red view) pinned to the top of scrollview, height of 200
    theScrollView.addConstraintsWithFormat("V:|[v0(==200)]", views: nativeText)

    //      mnemonicDescription (Green view) pinned 40 space to Red view, height of 300
    theScrollView.addConstraintsWithFormat("V:[v0]-40-[v1(==300)]", views: nativeText, mnemonicDescription)

    //      addButton (Blue view) pinned 40 space to Green view, height of 250, *and* pinned to bottom of scrollview
    theScrollView.addConstraintsWithFormat("V:[v0]-40-[v1(==250)]|", views: mnemonicDescription, addButton)

    // it could also be expressed in a single statement
    // comment out the above three lines of code, and
    // un-comment this line to see the same result
    //theScrollView.addConstraintsWithFormat("V:|[v0(==200)]-40-[v1(==300)]-40-[v2(==250)]|", views: nativeText, mnemonicDescription, addButton)

    // using those example heights and spacing comes to a total of 830, 
    // so it will scroll vertically a little bit on a iPhone 7+ (736 pts tall)
}
0
votes

This is not a very difficult thing to achieve. If you will research carefully you can find the answers to all you queries here itself.

Anyways I am providing you with the detailed code for the thing you want to achieve. Hope this help you.

Simply add this code below your ViewController Class.

let scrollView = UIScrollView()

override func viewDidLoad() {
    super.viewDidLoad()

    // Variables for setting the scrollView and Views inside scrollView
    let phoneHeight: CGFloat = self.view.frame.size.height
    let phoneWidth: CGFloat = self.view.frame.size.width
    var yPosition: CGFloat = 0
    var scrollViewHeight: CGFloat = 0


    // Setting scrollView attributes
    scrollView.frame.size.height = phoneHeight
    scrollView.frame.size.width = phoneWidth
    scrollView.frame.origin.x = 0
    scrollView.frame.origin.y = 0

    // Adding scrollView to the mainView
    self.view.addSubview(scrollView)

    // Creating subViews for the scrollView
    let view1 = UIView()
    let view2 = UIView()
    let view3 = UIView()
    let view4 = UIView()
    let view5 = UIView()

    // Adding the subVies in an array
    var subViewArray: [UIView] = []
    subViewArray.append(view1)
    subViewArray.append(view2)
    subViewArray.append(view3)
    subViewArray.append(view4)
    subViewArray.append(view5)

    // Adding the subViews to the scrollView
    for subView in subViewArray {

        // Setting the atributes for subViews
        // Fixed height of 200px and width adjusts according to the phoneSize
        subView.frame.size.height = 200
        subView.frame.size.width = phoneWidth
        subView.frame.origin.x = 0
        subView.frame.origin.y = yPosition

        // Adding the background color to the subViews
        subView.backgroundColor = UIColor.blue

        // Changing the yPosition and scrollViewHeight and adding a 20px margin for each subview in scrollView
        yPosition += 200 + 20
        scrollViewHeight += 200 + 20

        // Adding labels to the subviews
        let label1 = UILabel()
        label1.text = "Label Added"
        label1.textAlignment = .center
        label1.textColor = UIColor.white
        label1.frame.size.height = 30
        label1.frame.size.width = phoneWidth
        label1.frame.origin.x = 0
        label1.frame.origin.y = 10
        subView.addSubview(label1)

        self.scrollView.addSubview(subView)
        scrollView.contentSize = CGSize(width: phoneWidth, height: scrollViewHeight)
    }
}