I am trying to create an onboarding view such as Instagram stories with a progress bar on top of the view.
So far I was able to animate to the second or third index in the given time. This animation also changes stack view progress bar. But when I try to scroll to the next or previous collection view index I can not show this action inside the progress bar.
I can read the current page index with page control but can not reflect this reading to progress bar.
class OnboardingViewController: UIViewController, SegmentedProgressBarDelegate {
@IBOutlet weak var collectionView: UICollectionView!
@IBOutlet weak var stackView: UIStackView!
private var spb: SegmentedProgressBar!
var currentPage = 0
lazy var pageControl: UIPageControl = {
let pageControl = UIPageControl()
pageControl.numberOfPages = slides.count
return pageControl
}()
//Burası Presenter'dan gelecek.
var slides: [OnboardingSlide] = [
OnboardingSlide(title: "Delicious Dishes", image: #imageLiteral(resourceName: "1")),
OnboardingSlide(title: "World-Class Chefs", image: #imageLiteral(resourceName: "2")),
OnboardingSlide(title: "Instant World-Wide Delivery", image: #imageLiteral(resourceName: "3"))
]
override func viewDidLoad() {
super.viewDidLoad()
spb = SegmentedProgressBar(numberOfSegments: slides.count, duration: 3)
spb.frame = CGRect(x: 15, y: 56, width: collectionView.frame.width - 30, height: 4)
spb.delegate = self
spb.topColor = UIColor.white
spb.bottomColor = UIColor.white.withAlphaComponent(0.25)
spb.padding = 2
collectionView.delegate = self
collectionView.dataSource = self
stackView.addArrangedSubview(spb)
spb.startAnimation()
collectionView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tappedView)))
}
func segmentedProgressBarChangedIndex(index: Int) {
updateView(index: index)
}
override var prefersStatusBarHidden: Bool {
return true
}
func segmentedProgressBarFinished() {
print("Finished!")
}
@objc private func tappedView() {
spb.isPaused = !spb.isPaused
}
private func updateView(index: Int) {
print("index: \(index)")
let indexPath = IndexPath(row: index, section: 0)
collectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
@IBAction func loginButtonTapped(_ sender: UIButton) {
}
@IBAction func signupButtonTapped(_ sender: UIButton) {
}
}
extension OnboardingViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return slides.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: OnboardingCollectionViewCell.identifier, for: indexPath) as! OnboardingCollectionViewCell
cell.setup(slides[indexPath.row])
return cell
}
}
extension OnboardingViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.frame.width, height: collectionView.frame.height)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let width = scrollView.frame.width
currentPage = Int(scrollView.contentOffset.x / width)
pageControl.currentPage = currentPage
updateView(index: currentPage)
print("current page: \(currentPage)")
}
}
I have used https://github.com/D-32/SegmentedProgressBar
as the segmentedProgressBar
class OnboardingCollectionViewCell: UICollectionViewCell {
static let identifier = String(describing: OnboardingCollectionViewCell.self)
@IBOutlet weak var slideImageView: UIImageView!
@IBOutlet weak var slideTitleLabel: UILabel!
func setup(_ slide: OnboardingSlide) {
slideImageView.image = slide.image
slideTitleLabel.text = slide.title
}
}
struct OnboardingSlide {
let title: String
let image: UIImage
}
extension OnboardingViewController: UICollectionViewDelegateFlowLayout {
func scrollViewWillBeginDecelerating(_ scrollView: UIScrollView) {
if scrollView.panGestureRecognizer .translation(in: view).x > 0 {
spb.rewind()
} else {
spb.skip()
}
}
}
with this, I was able to understand if collection view was scrolled left or right. Thus calling related functions inside the spb does the trick.