19 Replies
      Latest reply on Jan 13, 2020 11:37 AM by uncletr
      uncletr Level 1 Level 1 (0 points)

        I want to use a Scrollview on the middle 2/3 of the screen so I did the following:

         

        1) I added a BaseView UIView to the middle 2/3 of my MainViewController and set the constraints to the following:

         

        leading =0

        trailing =0

        top to safe area = 150

        bottom to safe area = 150

         

        2) I added a MyScrollView inside the BaseView and set the constraints as follows:

        Note: All MyScrollview constraints remain RED after setting these constraints  :>(

         

        leading = 0

        trailing = 0

        top = 0

        bottom = 0

         

        3) I added a MyDataView UIView object inside the MyScrollView .  The MyDataView starts at (0,0) and has a size of 500x500.  I tried setting constraints on MyDataView to the following values but the top and leading constraints remain RED, most likely because the MyScrollView constraints are RED (see 2 above)

         

        top=0

        leading=0

        width=500

        height=500

         

         

        4) In the viewDidLoad function I added the following:

         

        ScrollView.delegate = self

        ScrollView.contentsize  = MyDataView.frame.size

         

        5) I added various objects (buttons, labels, etc.) in the MyDataView UIView and tried to set constraints on these objects but the constraints are all RED as well.  

         

        Questions:

        1) I am setting up the ScrollView properly so it can be used for 2/3 of the screen area only?

         

        2) How can I set valid constraints for the objects placed in the MyDataView and have them be a nice BLUE color?

        • Re: How to assign constraints to a Scrollview which covers part of the screen only?
          Claude31 Level 8 Level 8 (7,845 points)

          If you set constant at 150, that will not be 2/3 in all cases (e.g., landscape, or iPad).

               :> You should compute this value depending on screen height

           

          1) I am setting up the ScrollView properly so it can be used for 2/3 of the screen area only?

          Do you get what you expect ? Otherwise, what do you get ?

          Note: All MyScrollview constraints remain RED after setting these constraints  :>(

          Why do you create a BaseView and put the Scroll inside ?

          - You'd probably better create the Scroll at top hierarchy level

               Set its constraints

               leading =0

               trailing =0

               top to safe area = 150

               bottom to safe area = 150

          - then put the BaseView inside the scrollView

               Set its constraints relative to ScrollView

               leading = 0

               trailing = 0

               top = 0

               bottom = 0

          - Put the objects inside BaseView

          If the warning is about contentSize ambiguity, they should disappear

          May have a look here: h ttp://synappse.co/blog/uiscrollview-has-ambiguous-scrollable-content-height/

           

          2) How can I set valid constraints for the objects placed in the MyDataView and have them be a nice BLUE color?

          BLUE color for what type of objects ???

          To set constraint, use autolayout:

          - place the object inside MyDataView

          - control-drag from the object to MyDataView to set top, leading… or other

           

          Note: These are not Swift questions. You should move your post to Interface Builder section.

            • Re: How to assign constraints to a Scrollview which covers part of the screen only?
              uncletr Level 1 Level 1 (0 points)

              >>If you set constant at 150, that will not be 2/3 in all cases (e.g., landscape, or iPad).

              Yes, understood  :>)    I am just reporting my issue in a general fashion so I try to keep my explanation/summary to a bare minimum so I do not get into the super details of exactly what I am doing,  My point is that I do not want to have a ScrollView covering the complete screen.  Just assume I am using iPhone 8 in portrait mode and I only want 2/3 of the screen to be scrollable.

               

              >>Why do you create a BaseView and put the Scroll inside ?

              I believe I read a ScrollView must have all of it's constraints (ie: leading, trailing, top and bottom) set to zero(0) for it to work properly.  is this true?   Assuming this is true, then if I want the Scrollview to cover the complete ViewController screen then this is easy to do and does not involve me creating a BaseView UIVIew, however, since I only want the ScrollView to cover 2/3 of the screen then the only way to have ScrollView constraints all being zero(0) is if I put the ScrollView into a BaseView UIView.   Basically, the BaseView UIView covers 2/3 of the screen and the ScrollView is placed inside the BaseView, thus allowing me to set all constraints of the ScrollView to 0.

               

              Are you saying I can place a ScrollView object onto the ViewController area and set constraints so the ScrollView only covers 2/3 of the screen?

               

              >>Do you get what you expect ? Otherwise, what do you get ?

              Here is my first main issue simply described:

               

              Issue #1

              I place a BaseView UIView on to the ViewController and set the BaseView constraints so it covers 2/3 of the screen.  This works nicely and all constraints are BLUE.   I now place a ScrollView inside the BaseView and set the ScrollView cosntraints (ie: leading, trailing, top and bottom) to be zero(0).   After this, my issue is that all of the ScrollView constraints are RED.  Why are the ScrollView constraints not all BLUE at this point?

               

              >> You'd probably better create the ScrollView at top hierarchy level (leading/trailing=0 and top/bottom=150)

              >> then put the BaseView inside the ScrollView (leading/trailing/top/bottom=0)

              This would mean the BaseView would be the same exact size of the ScrollView.  The objects which I am dealing with cover a 500x500 UIView area, thus I need scrolling capabilities.  As a result, I cannot place all of the objects into a UIView which is the same exact size as the ScrollView, as you are suggesting.

               

              Issue #2

              I am using interface builder to place UIViews and ScrollView into my storyboard.  The UIView which has all of my objects (buttons, labels, etc.) has a size of 500x500 (for example).  This UIView needs to go inside of the ScrollView to allow scrolling to eventually occur.  I would like to set various constraints on the objects (buttons, labels, etc.) located within the UIView, however, I cannot set valid BLUE constraints on these objects until I can set valid BLUE constraints for the UIView and for the ScrollView first.

                • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                  Claude31 Level 8 Level 8 (7,845 points)

                  Are you saying I can place a ScrollView object onto the ViewController area and set constraints so the ScrollView only covers 2/3 of the screen?

                   

                  Yes, as explained in the link I posted.

                   

                  The idea to have UIView inside is to silent some (erroneous ?) IB warnings that content of ScrollView height or width are ambiguous

                  That may explain your #3 concern "Why are the ScrollView constraints not all BLUE at this point?"

                   

                  As a result, I cannot place all of the objects into a view which is the same exact size as the ScrollView, as you are suggesting.

                  In some case I have a ScrollView

                   

                  OK, I'll try to fully implement a case, inserting an image into the View in the ScrollView.

                    • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                      Claude31 Level 8 Level 8 (7,845 points)

                      Well, I did it as I said. The view inside the scrollView has the size of the scrollView (could be larger, so that you can position objects beyond the scrollView limit).

                      The image inside this view is larger, that is not a problem.

                       

                      It was a bit tricky (and honestly not really useful) to silence all IB warnings, but I managed to do it, defining constraints:

                      - To position the scrollView relative to safe area and specifying its witdh and height (that seem problematic to me, somehow overconstrained) ; but otherwise, I get warnings

                      - the view inside has the 4 constraints (left, top, bottom, right, Plus center horizontally and vertically (same comment here)

                      - for the image, I added 4 constraints (the struts with the little red lines): but removing them does not change anything.

                      - its size does not matter as I set it in code, but it must be larger that the scrollView to see the scroll

                       

                      Finally, in code:

                       

                          private var imageSize = CGSize(width: 960, height: 640)
                      
                          override func viewDidLoad() {
                          
                              super.viewDidLoad()
                      
                              // Do any additional setup after loading the view.
                              imageView.frame.size = imageSize
                      
                              scrollView.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
                          }
                      
                          override func viewDidLayoutSubviews() {
                            
                               scrollView.contentSize = self.imageSize 
                          }

                       

                       

                      If you want to work on view larger that the viewController (for the content view), you can either:

                      - do it by hand, selecting objects in the list and setting the position or constraint without viewing it inside the viewController (not very easy)

                      - or use freeform for a while

                      - or create a xib for the view

                      For the latter 2, read this:

                      https://stackoverflow.com/questions/25682729/ios-storyboard-how-do-you-edit-a-content-view-larger-than-screen-in-a-uiscrollv

                        • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                          uncletr Level 1 Level 1 (0 points)

                          >>May be have a look here: h ttp://synappse.co/blog/uiscrollview-has-ambiguous-scrollable-content-height/

                          This webpage indicates setting the ScrollView and UIView to have constraints all set to "0", which will not work for me.  This example shows how the UIView gets larger when more and more text is added to the TextField thus pushing the UIButton (and text) out of the visual screen area, thus allowing scrolling to be initiated.   I am assuming when the ScrollView constraints are all set to "0" then they are all RED for this guy as well, but he never mentions this at all

                           

                          >>If you want to work on view larger that the viewController (for the content view), you can either:

                          - do it by hand, selecting objects in the list and setting the position and constraint without viewing it inside the viewController

                          - or use freeform for a while

                          - or create a xib for the view

                          This is not a problem.  I simply reposition the content UIView, as required, within the viewController so I can see all objects which were previously off the screen.  I can then assign constraints and positions as desired.  This is not that bad as I am not dealing with ScrollViews that often.  If I was constantly dealing with ScrollViews, then this technique would eventually get annoying.

                           

                           

                          For testing, I created a brand new Xcode project and did the following:

                           

                          1) I added a ScrollView with the following constraints:

                           

                             leading safe area = 0

                             trailing safe area = 0

                             top to safe area = 150

                             bottom to safe area = 150

                           

                          • There are RED lines around the scrollview and a warning which states the "content size is ambiguous"
                          • I tried adding fixed width(375) and height(367) constraints to the ScrollView to see if the RED lines would go away (based on your comment) but they did not.   I then removed these width/height constraints since they did not help and really should not be required anyway.   Are you saying you were able to get the RED cosntraint lines to turn to BLUE by adding width/height constraints somehow?
                          • At this point, if you switch to "Landscape" mode you will see the ScrollView object does not resize itself based on the assigned constraints, which is odd.   I guess then means I cannot assume the ScrollView dimensions will be properly set when my application enters Landscape mode.  (Note: To resolve this issue, perhaps we need to place the ScrollView inside of a BaseUIView object, whose constraints are set as desired, and then ensure the ScrollView frame size is always equal to the BaseUIView? :>)
                          • In the viewDidLoad() I have the following  -->      myScrollView.contentSize = myUIView.frame.size
                          • The UIView is where I am planning on adding all of my buttons and labels which the user can scroll around and see.
                          • I do not want to set the UIView leading, trailing, top, bottom constraints to be 0 (like you did) since I do not want the UIView to be the same size as the ScrollView.  I need the UIView dimensions to be larger than the ScrollView so scrolling will be allowed.   I am going to use the Auto Layout "Vary for Traits" option to set different button/label/etc. constraints depending on whether I am in Portrait or Landscape modes so I need to be able to work with the complete UIView dimensions.

                           

                           

                          Questions:

                          a) Is there a way to resolve the ScrollView "content size is ambiguous" warning in interface builder to make all constraint lines turn BLUE?

                           

                          b) In the code, I make sure the UIView height/width are correct and also make sure the "ScrollView.contentsize" is set appropriately.  In order to set valid (BLUE) constraints on the objects (buttons, labels, etc.) located within the UIVIew, I must first set valid (BLUE) constraints for the UIView itself first.  As a result, I set the following constraints for the UIView:

                           

                             leading = 0

                             top = 0

                             width = 700

                             height = 700

                           

                          I then set valid (BLUE) constraints for all buttons, labels, etc.  located within the UIView.

                           

                          When I run the application and attempt to scroll, I see the "scrollViewDidScroll( )" UIScrollViewDelegate function IS being called repeatedly, but no actual scrolling of the objects is occurring visually.  The UIButtons located in the UIView can be clicked.

                           

                          I discovered if I remove the UIView four constraints (leading, top, width and height) then scrolling now works visually, but none of the UIButtons are clickable.  All weird stuff. 

                           

                          Any idea what is going on here?

                            • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                              Claude31 Level 8 Level 8 (7,845 points)

                              a) Is there a way to resolve the ScrollView "content size is ambiguous" warning in interface builder to make all constraint lines turn BLUE?

                               

                              If this code works OK, you should just ignore the warning (that's what I do !)

                              Trying to clear creates real complications essentially useless IMHO.

                                • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                                  uncletr Level 1 Level 1 (0 points)

                                  my code does not work.  I have been trying for two days.  I always dread trying to work with a ScrollView since I never can get it working.

                                   

                                  The simple issues are:

                                   

                                  1) Put ScrollView into ViewController and assign these 4 constraints --> leading/trailing safe area=0  and  top/bottom safe area = 150

                                  • ScrollView constraints remain RED
                                  • If you switch to Landscape mode then ScrollView dimensions do not change

                                   

                                  2) Put UIView into ScrollView with these dimensions --> x=0, y=0, width=500, height=500

                                  • I cannot assign constraints to UIView since ScrollView constraints are not set

                                   

                                  3) Put UIButton into UIView

                                  • I cannot assign constraint to UIButton since UIView constraints are not set

                                   

                                   

                                  Due to these issues, when I use a ScrollView I eventually end up doing one of the following:

                                   

                                  a) Never assign constraints to any objects located within the content view UIView and update object positions via the code only.

                                    OR

                                  b) Position the objects in the content view UIView and ensure they do not have to change positions when switching between Portrait and Landscape modes.   Basically, just allow the ScrollView to scroll through the same looking objects no matter what orientation I am in.

                                   

                                  It seems like I am going to need to choose (a) or (b) again and not really layout the objects via constraints like I want to.  It just means I have to assign a name to eveery single object located in the UIView and then write more code to manually position them during an orientation change.

                                    • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                                      Claude31 Level 8 Level 8 (7,845 points)

                                      Fore sure, auto layout for ScrollViews is very confusing.

                                       

                                      I looked at those 2 references:

                                      h ttps://www.freecodecamp.org/news/how-to-use-auto-layout-with-uiscrollview-for-ios-b94b8687a4cc/

                                      But you will see that the red dot in IB is always here, meaning there are still error messages

                                       

                                      h ttps://useyourloaf.com/blog/scroll-view-layouts-with-interface-builder/

                                      recommended here: https://stackoverflow.com/questions/56570660/how-to-fix-scrollable-content-size-ambiguity-in-xcode-11-ios-12-ios-13-usin

                                       

                                      with the following remarks:

                                       

                                      I stacked with that problem as well. Found a good guide that helped me:

                                      h ttps://useyourloaf.com/blog/scroll-view-layouts-with-interface-builder/

                                      Basically what you need is 9 constraints (assuming you want to scroll only vertically):

                                      1-4: ScrollView to Superview (top, bottom, leading, trailing). Make sure to connect it to parent view and not to safe area.

                                      5-8: Content view to Content Layout guide (top, bottom, leading, trailing).

                                      1. Content view Width equals width to Frame Layout Guide.

                                       

                                      But there may well be some bug in XCode as well.

                                       

                                      EDITED.

                                      Looks like the trick is to disable Content layout guide, in the Size Inspector for ScrollView (at the top of the inspector)

                                      That effectively cleared the red outlines errors. Now, changing orientation also changes the scrollView size.

                                      I created an ImageView inside

                                      I ended up with:

                                      - ScrollView, with 4 constraints to its superView

                                      - imageView with constraints to its superView (the scrollView)

                                       

                                      and code

                                       

                                      class InitialViewController: UIViewController {
                                      
                                          @IBOutlet weak var scrollView: UIScrollView!  
                                          @IBOutlet weak var imageView: UIImageView!
                                      
                                          private var imageSize = CGSize(width: 1920, height: 1280)     // Made it very large to see scroll
                                         
                                          override func viewDidLoad() {
                                              super.viewDidLoad()
                                              // Do any additional setup after loading the view.
                                              imageView.frame.size = imageSize 
                                      
                                              scrollView.autoresizingMask = [UIView.AutoresizingMask.flexibleWidth, UIView.AutoresizingMask.flexibleHeight]
                                          }
                                      
                                          override func viewDidLayoutSubviews() {
                                             
                                              scrollView.contentSize = self.imageSize
                                          }
                                      
                                      }
                        • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                          uncletr Level 1 Level 1 (0 points)

                          Claude,

                           

                          Ok, I created a brand new test project.

                           

                          1) I placed a Scrollview (with light blue background) into the default ViewController and set ScrollView constraints as follows:

                           

                               leading = 0 to safe area

                               trailing = 0 to safe area

                               top = 150 to safe area

                               bottom = 150 to safe area

                           

                          2) I added a ContentView UIView (with yellow background) inside the ScrollView with the folliowing values and no constraints set at this time:

                           

                              X = 0

                              Y = 0

                              Width = 700

                              Height = 700

                           

                          3) I added many buttons and labels inside the ContentView which have been positioned down the left side of the ContentView in a vertical fashion from Y=0 to Y=600 so some of the buttons/labels go outside the display viewing area.

                           

                          4) Here is the code:

                           

                          import UIKit
                          
                          class ViewController: UIViewController
                          {
                              @IBOutlet weak var ScrollView: UIScrollView!
                              @IBOutlet weak var ContentView: UIView!
                                
                              override func viewDidLoad()
                              {
                                  super.viewDidLoad()
                                  ScrollView.delegate = self
                              }
                          
                              override func viewDidLayoutSubviews()
                              {
                                  super.viewDidLayoutSubviews()
                                  print("viewDidLayoutSubviews")
                          
                                  ScrollView.contentSize = ContentView.frame.size
                              }
                          }
                          
                          extension ViewController: UIScrollViewDelegate
                          {
                              func scrollViewDidScroll(_ scrollView: UIScrollView)
                              {
                                  print("scrolling is occurring.  You can see the ScrollView scrollbars moving as well")
                              }
                          }

                           

                           

                          4) In the size inspector for the ScrollView, I unchecked the "Content Layout Guides" option box.

                           

                          Results:

                           

                          In IB...

                          - The constraints of the ScrollView are still RED and switching to landscape in IB does not resize the ScrollView dimensions

                          - Still receive the "Scrollable content size is ambiguous for Scroll View" warning

                           

                          When running the application...

                          - The ContentView contents CAN be scrolled up/down/left/right to see the full UIView (as previously)

                          - Switching the landscape mode resizes the scrollview area (as previously)

                           

                          Issues which still remain as before:

                          • I cannot assign constraints to UIButtons/UILabels located within the ContentView since no ContentView constraints are set.  Setting these constraints is the main goal of mine.
                          • When I set the following 4 constraints on the ContentView, then scrolling no longer works when running the application, although you can see scrolling events are being processed and also notice the scrollbars on the ScrollView are moving around as well.

                           

                                   leading = 0

                                   top = 0

                                   width = 700

                                   height = 700

                           

                           

                          Questions for you

                          1) You indicated you set ImageView constraints.  What exact ImageView constraints did you set?

                          2) Instead of using an ImageView, can you try a UIView and place UIButtons inside the UIView and see if you can set constraints on the buttons?

                            • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                              Claude31 Level 8 Level 8 (7,845 points)

                              Compared to your set up, creating a brand new ViewController:

                              - Step 1: OK

                              - Step 2: all red lines, and warning: (red arrow): ambiguous scrollable content

                              - Step 3: OK, created 8 labels down to y = 600 in ContentView

                              - Step 4: same

                               

                              Run the code: I can scroll. All work OK

                              - Step 5

                              - turn off Content Layout Guides: lines stay red and ambiguous scrollable content

                              - Added constraints for the contentView : leading, trailing, and Top (0: content.top = superview.top + 0), Bottom (300: superview.bottom = content.bottom + 300), width (700 as proposed), height (700 as proposed)

                                   => Lines turn blue

                                   => red warning disappear

                              BTW: turn ON Content Layout Guides does not cause problem now !!!!

                               

                              Run code: OK in Portrait and in Landcape (even though contentView is a bit narrow vertically.

                               

                              - Step 6: turned landscape in IB: redrawn correctly

                               

                              Questions for you (me)

                              1) You indicated you set ImageView constraints.  What exact ImageView constraints did you set?

                                   Well see question 2, I created a test case with UIView

                              2) Instead of using an ImageView, can you try a UIView and place UIButtons inside the UIView and see if you can set constraints on the buttons?

                                   I placed Labels not buttons, but that does not make a difference.

                                   To be sure, I added 8 buttons next to the labels. Still works OK.

                               

                               

                              So, the conclusion is:

                              Need to set constraints Top (0: content.top = superview.top + 0), Bottom (300: superview.bottom = content.bottom + 300)

                                • Re: How to assign constraints to a Scrollview which covers part of the screen only?
                                  uncletr Level 1 Level 1 (0 points)

                                  >> Added constraints for the contentView : leading, trailing, and Top (0: content.top = superview.top + 0), Bottom (300: superview.bottom = content.bottom + 300), width (700 as proposed), height (700 as proposed)

                                  >>     => Lines turn blue

                                  >>     => red warning disappear

                                   

                                  While "Content Layout Guides" is off I then click on the ContentView to set constraints.  When using Auto Layout in IB, the only constraint options I have available to select for ContentView are the following:

                                   

                                     leading = 0 to ScrollView

                                     top        = 0 to ScrollView

                                     trailing  = -325 to Scrollview

                                     bottom = -333 to Scollview

                                     width    = 700

                                     height   = 700

                                   

                                  • How were you able to set constraints for your ContentView to be pinned to the SuperView?
                                  • Are you using Auto Layout to set constraints?
                                  • Is your ContentView located within the Scrollview?

                                   

                                  PS:  Thanks for all the help !  Looks like we are getting close