Change page on UIScrollView

Viewed 52937

I have a UIScrollView with 10 pages. I am able to flick between them. I also want to have 2 buttons (a back button and a next button) which when touched will go to the previous or next page. I can't seem to figure out a way to do this though. A lot of my code comes from Apple's page control sample code. Can anybody help?

Thanks

12 Answers

You just tell the buttons to scroll to the page's location:

CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * pageNumberYouWantToGoTo;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];

scrollRectToVisible was not working for me, so I had to animate the contentOffset. This code works in swift 3.

func scrollToPage(_ page: Int) {
    UIView.animate(withDuration: 0.3) { 
        self.scrollView.contentOffset.x = self.scrollView.frame.width * CGFloat(page)
    }
}

For Swift 3 this is an extension that I find very convenient:

extension UIScrollView {
    func scrollToPage(index: UInt8, animated: Bool, after delay: TimeInterval) {
        let offset: CGPoint = CGPoint(x: CGFloat(index) * frame.size.width, y: 0)
        DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: {
            self.setContentOffset(offset, animated: animated)
        })
    }
}

And you call it like this:

scrollView.scrollToPage(index: 1, animated: true, after: 0.5)

I wanted to implement an image slider with automatic scrolling using a UIScrollView and a UIStackView. This is what I ended up with and it's working pretty well. I a using PureLayout for AutoLayout:

class ImageSlideShow: UIView {

private let scrollView = UIScrollView()
private var images: [UIImage] = []
private var scrollTimer: Timer?

init() {
    super.init(frame: .zero)
    self.setupView()
}

required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

public func setImages(_ images: [UIImage], initialIndex: Int = 0) {
    self.images = images
    self.scrollTimer?.invalidate()
    self.scrollView.removeAllSubviews()
    
    let stackView = self.getStackView()
    self.scrollView.addSubview(stackView)
    
    stackView.autoMatch(.height, to: .height, of: self.scrollView)
    stackView.autoPinEdgesToSuperviewEdges()
    
    self.images.forEach { image in
        let imageView = UIImageView(image: image)
        imageView.contentMode = .scaleAspectFill
        stackView.addArrangedSubview(imageView)
        imageView.autoMatch(.width, to: .width, of: self.scrollView)
    }
    
    self.setupScrollTimer()
}

private func getStackView() -> UIStackView {
    let stackView = UIStackView()
    stackView.axis = .horizontal
    stackView.alignment = .fill
    stackView.distribution = .equalSpacing
    stackView.spacing = 0
    return stackView
}

private func setupScrollTimer() {
    self.scrollTimer = Timer.scheduledTimer(
        timeInterval: 0.5,
        target: self,
        selector: #selector(scroll), userInfo: nil,
        repeats: true
    )
}

@objc private func scroll() {
    let currentPage = self.scrollView.contentOffset.x / scrollView.frame.size.width
    var nextPage = currentPage + 1
    
    var frame: CGRect = self.scrollView.frame
    
    if nextPage >= CGFloat(self.images.count) {
        nextPage = 0
    }
    
    frame.origin.x = frame.size.width * CGFloat(nextPage)
    self.scrollView.scrollRectToVisible(frame, animated: true)
}

private func setupView() {
    self.backgroundColor = Colors.cream
    self.setupScrollView()
}

private func setupScrollView() {
    self.addSubview(self.scrollView)
    self.scrollView.autoPinEdgesToSuperviewEdges(with: .margin(Metrics.paddingDoublePlus))
    self.scrollView.isPagingEnabled = true
    self.scrollView.layer.cornerRadius = Metrics.cornerRadius
    self.scrollView.showsHorizontalScrollIndicator = false
    self.scrollView.showsVerticalScrollIndicator = false
}

}

Related