0
votes

I have a UIScrollView which is a dashboard basically with relevant information for the user. It has a pager underneath and contains three UIViews at the moment.

I used to set the different views with a CGRect as the frame, setting the x offset to the width of the UIScrollView * the page number. This worked fine, but it was a hassle to make the UIScrollView disappear when scrolling in the UITableView underneath.

I am now using AutoLayout with constraints to display the information, which works fine. However, my UIScrollView is not scrolling anymore. It does not respond to any swipe gestures I perform. However, it does respond to taps in the pager, which shows me the offsets and constraints are right, I am just unable to scroll in it. Take a look:

Example

My UIScrollView is made up like this:

var dashboardView: UIScrollView = {

    let dashboardView = UIScrollView()
    dashboardView.translatesAutoresizingMaskIntoConstraints = false
    dashboardView.backgroundColor = UIColor.clear
    dashboardView.layer.masksToBounds = true
    dashboardView.layer.cornerRadius = 10
    dashboardView.isPagingEnabled = true
    dashboardView.showsHorizontalScrollIndicator = false
    dashboardView.showsVerticalScrollIndicator = false
    dashboardView.alwaysBounceHorizontal = false
    dashboardView.alwaysBounceVertical = false
    return dashboardView

}()

I then set the different views like so:

for index in 0..<3 {

    let currentDash = UIView()
    currentDash.backgroundColor = UIColor.lightGray
    currentDash.layer.cornerRadius = 10
    currentDash.layer.masksToBounds = false
    currentDash.translatesAutoresizingMaskIntoConstraints = false
    currentDash.isUserInteractionEnabled = false
    dashboardView.addSubview(currentDash)
    currentDash.topAnchor.constraint(equalTo: dashboardView.topAnchor).isActive = true
    currentDash.bottomAnchor.constraint(equalTo: dashboardView.bottomAnchor).isActive = true
    currentDash.leadingAnchor.constraint(equalTo: dashboardView.leadingAnchor, constant: dashboardWidth * CGFloat(index)).isActive = true
    currentDash.trailingAnchor.constraint(equalTo: dashboardView.leadingAnchor, constant: (dashboardWidth * CGFloat(index)) + dashboardWidth).isActive = true
    currentDash.widthAnchor.constraint(equalToConstant: dashboardWidth).isActive = true
    currentDash.heightAnchor.constraint(equalToConstant: dashboardHeight).isActive = true

}

When I remove the constraints (AutoLayout) and set it with frames it works perfectly, like this:

dashFrame.origin.x = dashboardWidth * CGFloat(index)
dashFrame.size = CGSize(width: dashboardWidth, height: dashboardHeight)
let currentDash = UIView(frame: dashFrame)

But then, because of setting the frame, the view doesn't scroll up as I would, which is why I want to use AutoLayout.

Any ideas or suggestions as to what I am doing wrong? My ScrollViewDidScroll() method simply gets not called, because a simple print doesn't return anything in my console.

I have tried setting the isUserInteractionEnabled property to false on the currentDash UIView, which was no success. I have also tried removing all constraints separately, some together, etc. - but also this doesn't work - I need a topAnchor, bottomAnchor, heightAnchor and widthAnchor at least.

Oh, and, of course, I set the contentSize property:

dashboardView.contentSize = CGSize(width: dashboardWidth * CGFloat(dashboardPager.numberOfPages), height: dashboardHeight)

Any suggestions or hints towards the right answer would be deeply appreciated. Thanks!

EDIT: I also set constraints for the UIScrollView itself:

dashboardView.topAnchor.constraint(equalTo: dashboardBG.topAnchor).isActive = true
dashboardView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: normalSpacing).isActive = true
dashboardView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -normalSpacing).isActive = true
dashboardView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
dashboardView.heightAnchor.constraint(equalToConstant: dashboardHeight).isActive = true

dashboardView.delegate = self
2
A common problem when using Scroll View is not properly defining the constraints. A scroll view does not have a set height. It gets its height from the content view it is to display. Within this content view a ScrollView needs to know the height and width of the content it is holding in order to know how much to scroll and which direction. Try to re-do your constraints from inside the scrollview out - Julian Silvestri
Based on your suggestion, I have edited my original post with the constraints I use for the UIScrollView itself. So these should be fine as well, I think. - PennyWise

2 Answers

3
votes

The issue is here

currentDash.leadingAnchor.constraint(equalTo: dashboardView.leadingAnchor, constant: dashboardWidth * CGFloat(index)).isActive = true
currentDash.trailingAnchor.constraint(equalTo: dashboardView.leadingAnchor, constant: (dashboardWidth * CGFloat(index)) + dashboardWidth).isActive = true

1- Regarding leading of the views , the leading of the first view should be pinned to the scrollView , the leading of the second view pinned to the trailing of the previous and so on , so

if index == 0{

   // make leading with scrolview leading
else
{

   // make leading with prevView trailing
}

So make a var initiated with scrollView and change end of for loop

2- Regarding the trailing , only the last view trailing be pinned to the trailing of the scrollview

if index == 2 { // last 

 // make trailing with scrollView 
}
1
votes

I eventually figured it out thanks to Sh_Khan’s answer. I held on to the original code, but removed the trailingAnchor for all indexes and added it only to the last index.

for index in 0..<3 {

    let currentDash = UIView()
    currentDash.backgroundColor = UIColor.lightGray
    currentDash.layer.cornerRadius = 10
    currentDash.layer.masksToBounds = false
    currentDash.translatesAutoresizingMaskIntoConstraints = false
    currentDash.isUserInteractionEnabled = false
    dashboardView.addSubview(currentDash)
    currentDash.topAnchor.constraint(equalTo: dashboardView.topAnchor).isActive = true
    currentDash.bottomAnchor.constraint(equalTo: dashboardView.bottomAnchor).isActive = true
    currentDash.leadingAnchor.constraint(equalTo: dashboardView.leadingAnchor, constant: dashboardWidth * CGFloat(index)).isActive = true
    currentDash.widthAnchor.constraint(equalToConstant: dashboardWidth).isActive = true
    currentDash.heightAnchor.constraint(equalToConstant: dashboardHeight).isActive = true 
    if index == 2 {
        currentDash.trailingAnchor.constraint(equalTo: dashboardView.trailingAnchor).isActive = true
    } 
}

Thanks for the help!