I've created a scroll view where the user can cycle through the pages that I've assigned. The first button leads to page1
as the starting page. However I would like the current starting page to be page 2 when I press button 2 that leads me to the page views but I can't seem to find a way around it,
My code in the ViewController
is as follows:
var pages : [View] {
get {
let page1: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page1.colorLabel.text = "Apartment A3"
page1.priceLabel.text = "N$ 504 500"
page1.imageView.image = UIImage(named: "apartment_a3_1")
let page2: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page2.colorLabel.text = "Apartment A4"
page2.priceLabel.text = "N$ 481 000"
page2.imageView.image = UIImage(named: "apartment_a4_1")
let page3: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page3.colorLabel.text = "Apartment A5"
page3.priceLabel.text = "N$ 541 000"
page3.imageView.image = UIImage(named: "apartment_a5_1")
let page4: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page4.colorLabel.text = "Apartment A6"
page4.priceLabel.text = "N$ 553 000"
page4.imageView.image = UIImage(named: "apartment_a6_1")
let page5: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page5.colorLabel.text = "Apartment A8"
page5.priceLabel.text = "N$ 588 000"
page5.imageView.image = UIImage(named: "apartment_a8_1")
let page6: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page6.colorLabel.text = "Apartment A9"
page6.priceLabel.text = "N$ 775 000"
page6.imageView.image = UIImage(named: "apartment_a9a1")
let page7: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page7.colorLabel.text = "Apartment A12"
page7.priceLabel.text = "N$ 775 000"
page7.imageView.image = UIImage(named: "apartment_a12_a")
return [page1, page2, page3, page4, page5, page6, page7]
}
}
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
//view.bringSubviewToFront(pageControl)
setupScrollView(pages: pages)
pageControl.numberOfPages = pages.count
pageControl.currentPage = 0
}
func setupScrollView(pages: [View]) {
//scrollView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height)
scrollView.contentSize = CGSize(width: view.frame.width * CGFloat(pages.count), height: view.frame.height)
scrollView.isPagingEnabled = true
for i in 0 ..< pages.count {
pages[i].frame = CGRect(x: view.frame.width * CGFloat(i), y: 0, width: view.frame.width, height: view.frame.height)
scrollView.addSubview(pages[i])
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x/view.frame.width)
pageControl.currentPage = Int(pageIndex)
}
}
I've tried to change PageControl.currentPage = 0
to 1
but no luck.
Couple notes...
First, you should be using auto-layout -- makes it much easier to manage the frames and the scroll view content.
Second, keep your size calculations relative to the scroll view's frame, not the view's frame... it will keep things more consistent, and avoid problems if you decide to make the scroll view not "full screen" (which you shouldn't do anyway, because you always want to respect the safe-area).
Third, if you only have 7 "pages" this approach should be fine. If you may have more than that, you can run into memory issues. If that's the case, you should look into either a UICollectionView
or UIPageViewController
.
So, assuming you can stick with the scroll view approach...
To "start at the second page" you can set the scroll view's .contentOffset.x
during viewDidLayoutSubviews
.
Start by adding a var
property to track the width of the scroll view's frame:
var scrollViewWidth: CGFloat = 0
then implement viewDidLayoutSubviews()
:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// we only want to call this once
if scrollViewWidth != scrollView.frame.width {
scrollViewWidth = scrollView.frame.width
scrollView.contentOffset.x = scrollView.frame.width
}
}
Here's a quick look at some changes you might want to make to take advantage of the benefits of auto-layout:
class ViewController: UIViewController {
var pages : [View] {
get {
let page1: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page1.colorLabel.text = "Apartment A3"
page1.priceLabel.text = "N$ 504 500"
page1.imageView.image = UIImage(named: "apartment_a3_1")
let page2: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page2.colorLabel.text = "Apartment A4"
page2.priceLabel.text = "N$ 481 000"
page2.imageView.image = UIImage(named: "apartment_a4_1")
let page3: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page3.colorLabel.text = "Apartment A5"
page3.priceLabel.text = "N$ 541 000"
page3.imageView.image = UIImage(named: "apartment_a5_1")
let page4: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page4.colorLabel.text = "Apartment A6"
page4.priceLabel.text = "N$ 553 000"
page4.imageView.image = UIImage(named: "apartment_a6_1")
let page5: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page5.colorLabel.text = "Apartment A8"
page5.priceLabel.text = "N$ 588 000"
page5.imageView.image = UIImage(named: "apartment_a8_1")
let page6: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page6.colorLabel.text = "Apartment A9"
page6.priceLabel.text = "N$ 775 000"
page6.imageView.image = UIImage(named: "apartment_a9a1")
let page7: View = Bundle.main.loadNibNamed("View", owner: self, options: nil)?.first as! View
page7.colorLabel.text = "Apartment A12"
page7.priceLabel.text = "N$ 775 000"
page7.imageView.image = UIImage(named: "apartment_a12_a")
return [page1, page2, page3, page4, page5, page6, page7]
}
}
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView(pages: pages)
pageControl.numberOfPages = pages.count
pageControl.currentPage = 0
}
var scrollViewWidth: CGFloat = 0
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// we only want to call this once
if scrollViewWidth != scrollView.frame.width {
scrollViewWidth = scrollView.frame.width
scrollView.contentOffset.x = scrollView.frame.width
}
}
func setupScrollView(pages: [View]) {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
let clg = scrollView.contentLayoutGuide
let flg = scrollView.frameLayoutGuide
scrollView.addSubview(stack)
NSLayoutConstraint.activate([
// constrain all 4 sides of stack view to scroll view's Content Layout Guide
stack.topAnchor.constraint(equalTo: clg.topAnchor),
stack.leadingAnchor.constraint(equalTo: clg.leadingAnchor),
stack.trailingAnchor.constraint(equalTo: clg.trailingAnchor),
stack.bottomAnchor.constraint(equalTo: clg.bottomAnchor),
// constrain height of stack view to scroll view's Frame Layout Guide
stack.heightAnchor.constraint(equalTo: flg.heightAnchor),
])
for i in 0 ..< pages.count {
// add each page to the stack view
stack.addArrangedSubview(pages[i])
// make each page the same width as the scroll view's Frame Layout Guide width
pages[i].widthAnchor.constraint(equalTo: flg.widthAnchor).isActive = true
}
scrollView.isPagingEnabled = true
scrollView.delegate = self
}
@IBAction func pageControlChanged(_ sender: UIPageControl) {
UIView.animate(withDuration: 0.3, animations: {
self.scrollView.contentOffset.x = CGFloat(sender.currentPage) * self.scrollView.frame.width
})
}
}
extension ViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageIndex = round(scrollView.contentOffset.x / scrollView.frame.width)
pageControl.currentPage = Int(pageIndex)
}
}
Edit - response to comment...
If you have buttons to "go to a page" you can implement a function like this:
func showPage(_ pg: Int) {
UIView.animate(withDuration: 0.3, animations: {
self.scrollView.contentOffset.x = CGFloat(pg - 1) * self.scrollView.frame.width
})
}
and call it with, for example:
showPage(5)