3

I have a scroll view that contains different options for logging into an application.

There are two buttons that I would like to anchor to the bottom of the view, unless the view becomes too small, then the view should scroll.

Having no constraint between "Login" and "Facebook" expectedly results in the infamous "ambiguous content height". Including a "top space to view" constraint means the buttons aren't anchored to the bottom.

Is there a way to include this "flexible space" using Auto layout alone? What can be done if not?

enter image description here

James Webster
  • 31,873
  • 11
  • 70
  • 114
  • Just Pin Facebook & Google buttons to the bottom of view. And the rest to the top. Is that something you want? – Oleg Shanyuk Sep 03 '15 at 11:39
  • 1
    `Having no constraint between "Login" and "Facebook" expectedly results in the infamous "ambiguous content height".` – James Webster Sep 03 '15 at 11:39
  • Aha. So, your login layout is inside scroll view, and you're looking for the way to scroll it (bounce), and to stick FB & 'Alphabet' to the bottom. Do the following: 1. Add all login controls into the view of "FreeForm" size, pin FB & Google to the bottom, add that `container` view into the scroll view; at viewDidLoad, or viewWillAppear update height of that `container` to the desired size. So, you'll get your bouncing screen and properly sticked buttons. – Oleg Shanyuk Sep 03 '15 at 11:41
  • 1
    Yes. `I have a scroll view that contains different options for logging into an application.` The view should only scroll when the space between "Login" and "Facebook" reaches a small enough threshold. – James Webster Sep 03 '15 at 11:44
  • So You can do this by increasing content size of ScrollView. And yes it is perfectly possible by using Auto layout. – Kampai Sep 03 '15 at 11:46
  • @Kampai, the content size of the scroll view is determined dynamically when using auto layout. – James Webster Sep 03 '15 at 11:47
  • Yes, So that will helpful you right? I mean if there is no space than scrollview increase content size and then you can scroll for below button. – Kampai Sep 03 '15 at 11:47
  • 1
    I'm not sure what you mean. I never set the content size. It's "figured out" automatically by auto layout. – James Webster Sep 03 '15 at 11:49
  • Oh, you can't connect constraints of objects inside scroll view to objects outside scroll view (at least, this is not what you want, trust me). You need the content view of scroll view size is calculated "automatically" based on the size of objects added to scroll view. But, you have to define the size of objects you're adding to scroll view. And the best is to add a single view, define it's size, and add all the controls you need inside that view. And yes, you have to set the size of that view explicit. (have width and height constraints?) – Oleg Shanyuk Sep 03 '15 at 12:01
  • How about using a transparent UIView between login and facebook? Login's bottom space 0 (zero) to UIView, and UIView's bottom space 0 (zero) to facebook. Then you can make UIView's height equals to ViewController's View (ScrollView's parent). You need calculate de multiplier of height constraint. – Thomás Pereira Dec 11 '15 at 15:34

2 Answers2

0

Please check what i've done. Maybe this will help you.

  • Take One View and add fb and google button init.
  • Give View To Scrollview Equal Widths and Equal Heights. and Center Horizontal and Vertical so Scrollview will get its contentsize. so If screen increase scrollview increase and UIView will also increase.
  • Give Fb and google to bottom constraint to UIView so doesnt matter if screen increase your button will stick to bottom.

Put all other things directly in UIScrollview or add it to UIView.

Please check below screenshot.Hope it helps.

Please check this


Edit by OP:

A little extra work was required on this answer to stop buttons overlapping if the screen is very short. (I can't post the exact code as it is the IP of my company, but as an overview:)

On layout subviews:

  • Check if the frame of the social logins view and the view at the bottom of the scroll view overlap by intersecting their frames.
    • The frames should both be in the same coordinate space. e.g. converted to window space.
  • Increase the content view's height constraint by the height of that intersection (and possibly a little extra padding)
  • Move the frame of the view containing the social logins down by the same amount.
James Webster
  • 31,873
  • 11
  • 70
  • 114
ChintaN -Maddy- Ramani
  • 5,156
  • 1
  • 27
  • 48
  • I see how this works. I'll give it a try when I get back to the office. – James Webster Sep 03 '15 at 12:21
  • This works quite well for all but the smallest of screens. Any ideas for this bit of the question: `unless the view becomes too small, then the view should scroll`. Otherwise, this could all be done without a scroll view. – James Webster Sep 03 '15 at 13:09
  • @JamesWebster You can give UIVIew to Scrollview BottomSpace which will be around 30. Give outlet of this constraint and then give 30 if iphone 4s and give 0 for other devices. So your View will scroll in 4s. Its just some settings. – ChintaN -Maddy- Ramani Sep 03 '15 at 13:42
  • I needed to bit extra using intersecting rects to figure out how much the scroll view should be extended, but I think I have it working for any screen size now. Thanks for the help – James Webster Sep 03 '15 at 14:24
-1

Check this out I had one case like your one. Have a look - This will sure help you to resolve constraints conflicts.

Create UIScrollView and set constrains with superview

// Create scrollview to display content
self.scrollView = UIScrollView()
self.scrollView.delegate = self
self.scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)
self.view.addSubview(self.scrollView)
scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive

// Visual formatting constraints of scrollview horizontal-vertical alignment with respect to view
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[scrollView]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["scrollView" : scrollView]))
self.view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[scrollView]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["scrollView" : scrollView]))

After creating scrollView, create subviews for scrollview and define its constraints:

[Here VariableView is a different class, it is a subclass of UIView it is not included with the code and it is just for reference. Replace your view with VariableView]

func createQuestionControls() {

    var previousControlView : VariableView! = nil

    for variable in self.consultation.variables {

        // Create custom view to add controls
        var controlView : VariableView! = VariableView()
        controlView.customTextDelegate? = self
        controlView.setVariableView(variable as! Variable)
        controlView.backgroundColor = UIColor.clearColor()
        controlView.setTranslatesAutoresizingMaskIntoConstraints(false)

        controlView.endEditing(true)

        self.scrollView.addSubview(controlView)

        // TOP Horizontal constraint
        var metrices = ["width" : self.view.bounds.width]
        self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[controlView(width)]", options: NSLayoutFormatOptions(0), metrics: metrices, views: ["controlView" : controlView]))

        if previousControlView == nil {

            // Top vertical constraint
            self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[controlView]", options: NSLayoutFormatOptions(0), metrics: nil, views: ["controlView" : controlView]))
        } else {

            // Top constraint to previous view
            self.scrollView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[previousControlView]-(10)-[controlView]", options: NSLayoutFormatOptions(0), metrics: nil, views: ["controlView" : controlView, "previousControlView" : previousControlView]))
        }
        previousControlView = controlView
    }

    // This below constraints will increase UIScrollView content size
    var constraint1 = NSLayoutConstraint.constraintsWithVisualFormat("H:[previousControlView]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["previousControlView" : previousControlView])
    self.scrollView.addConstraints(constraint1)

    var constraint2 = NSLayoutConstraint.constraintsWithVisualFormat("V:[previousControlView]|", options: NSLayoutFormatOptions(0), metrics: nil, views: ["previousControlView" : previousControlView])
    self.scrollView.addConstraints(constraint2)
}

The point to be noted here is if you have multiple subviews in UIScrollView then use bottom view (subview that is attached at last in scrollView), is used in constraint1 and constraint2 variables.

Kampai
  • 22,848
  • 21
  • 95
  • 95