Search code examples
objective-cswiftiphonexcodescrollview

UIImageView is not scrolling inside a scrollView


I am creating a scrollview with a page control. I have a scrollview added to my viewcontroller and inside the scrollview there is a UIImageView. But for some reason I cannot scroll it to the left or right side. Can anyone help me out to fix this problem?

My Code:

    var tutorialImages: [String] = ["1", "2", "3"]
var frame = CGRect.zero

func pageControll() {
    pageControllTutorial.numberOfPages = tutorialImages.count

    for i in 0..<tutorialImages.count {


        imageViewTutorial.frame = frame
        imageViewTutorial.image = UIImage(named: tutorialImages[i])
        scrollViewTutorial.addSubview(imageViewTutorial)
    }

    scrollViewTutorial.contentSize = CGSize(width: imageViewTutorial.frame.size.width * CGFloat(tutorialImages.count), height: imageViewTutorial.frame.size.height)

    scrollViewTutorial.delegate = self
}


func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
    var pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
    pageControllTutorial.currentPage = Int(pageNumber)
}

Solution

  • With the little bit of code you've shown, you're doing a number of things wrong.

    Based on this line:

    imageViewTutorial.image = UIImage(named: tutorialImages[I])
    

    it looks like you have one UIImageView and you are setting its .image property 3 times, instead of creating 3 different image views.

    Also, there is nothing in your code indicating how you are setting the frames of the image views.

    I highly recommend using auto-layout instead of explicit frames - makes things much, much easier going forward.

    Here is a complete example. It will create a square (1:1 ratio) scroll view 20-pts from the top with 20-pts padding on each side, and a UIPageControl below. It then adds a horizontal UIStackView to the scroll view. That stack view will hold the image views. Once the image views are added, the stack view will automatically define the "scrollable area" -- no need for calculating .contentSize.

    Here's what it will look like:

    enter image description here

    Everything is done in code, so just assign the class of an empty view controller to SlidesExampleViewController ... no @IBOutlet or @IBAction connections needed.

    class SlidesExampleViewController: UIViewController, UIScrollViewDelegate {
    
        lazy var pageControl: UIPageControl = {
            let v = UIPageControl()
            v.backgroundColor = .brown
            return v
        }()
    
        lazy var scrollView: UIScrollView = {
            let v = UIScrollView(frame: .zero)
            v.backgroundColor = .yellow
            v.delegate = self
            return v
        }()
    
        lazy var stackView: UIStackView = {
            let v = UIStackView()
            v.axis = .horizontal
            v.alignment = .fill
            v.distribution = .fill
            v.spacing = 0
            return v
        }()
    
        let tutorialImages: [String] = ["1", "2", "3"]
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            view.backgroundColor = .white
    
            scrollView.translatesAutoresizingMaskIntoConstraints = false
            stackView.translatesAutoresizingMaskIntoConstraints = false
            pageControl.translatesAutoresizingMaskIntoConstraints = false
    
            view.addSubview(scrollView)
            view.addSubview(pageControl)
            scrollView.addSubview(stackView)
    
            let v = view.safeAreaLayoutGuide
            let g = scrollView.contentLayoutGuide
    
            NSLayoutConstraint.activate([
    
                // constrain scroll view to top, leading, trailing with 20-pts "padding"
                scrollView.topAnchor.constraint(equalTo: v.topAnchor, constant: 20.0),
                scrollView.leadingAnchor.constraint(equalTo: v.leadingAnchor, constant: 20.0),
                scrollView.trailingAnchor.constraint(equalTo: v.trailingAnchor, constant: -20.0),
    
                // constrain scroll view height equal to scroll view width
                scrollView.heightAnchor.constraint(equalTo: scrollView.widthAnchor),
    
                // constrain stack view to all 4 sides of scroll view's contentLayoutGuide
                stackView.topAnchor.constraint(equalTo: g.topAnchor),
                stackView.bottomAnchor.constraint(equalTo: g.bottomAnchor),
                stackView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
                stackView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
    
                // constrain stack view height equal to scroll view height
                stackView.heightAnchor.constraint(equalTo: scrollView.heightAnchor),
    
                // constrain page control width to 80% of scroll view width
                pageControl.widthAnchor.constraint(equalTo: scrollView.widthAnchor, multiplier: 0.8),
    
                // constrain page control top to 8-pts below scroll view bottom
                pageControl.topAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: 8.0),
    
                // constrain page control centerX to centerX of scroll view
                pageControl.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor, constant: 0.0),
    
            ])
    
            tutorialImages.forEach { name in
                if let img = UIImage(named: name) {
                    let imgView = UIImageView(image: img)
                    stackView.addArrangedSubview(imgView)
                    imgView.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
                }
            }
    
            pageControl.numberOfPages = tutorialImages.count
    
            scrollView.isPagingEnabled = true
    
        }
    
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
            pageControl.currentPage = Int(pageIndex)
        }
    }