Commit fac5e487 by Dmitry Stepanets

Working on scroll animation

parent e68fcfc6
...@@ -11,6 +11,8 @@ class OnboardingPageControl: UIView { ...@@ -11,6 +11,8 @@ class OnboardingPageControl: UIView {
//Private //Private
private let kSpacePerDot: CGFloat = 10 private let kSpacePerDot: CGFloat = 10
private let kDotSize: CGSize = .init(width: 9, height: 9) private let kDotSize: CGSize = .init(width: 9, height: 9)
private let kIndicatorSize: CGSize = .init(width: 6, height: 6)
private var currentPageIndex = 0
private let totalPagesCount: Int private let totalPagesCount: Int
private let indicator = CAShapeLayer() private let indicator = CAShapeLayer()
private var dots = [CAShapeLayer]() private var dots = [CAShapeLayer]()
...@@ -18,50 +20,71 @@ class OnboardingPageControl: UIView { ...@@ -18,50 +20,71 @@ class OnboardingPageControl: UIView {
init(totalPagesCount: Int) { init(totalPagesCount: Int) {
self.totalPagesCount = totalPagesCount self.totalPagesCount = totalPagesCount
super.init(frame: .zero) super.init(frame: .zero)
self.backgroundColor = .gray
prepareDots() prepareDots()
prepareIndicator() prepareIndicator()
} }
override func layoutSubviews() { override func layoutSubviews() {
super.layoutSubviews() super.layoutSubviews()
self.frame.size.width = CGFloat(totalPagesCount) * kDotSize.width + kSpacePerDot * (CGFloat(totalPagesCount) - 1)
self.frame.size.height = kDotSize.height
//Dots //Update Y positions
for (index, dot) in dots.enumerated() {
let cgIndex = CGFloat(index)
let space = index == 0 ? 0 : kSpacePerDot
let rect = CGRect(origin: .init(x: cgIndex * (kDotSize.width + space), y: 0), size: kDotSize)
dot.path = CGPath(ellipseIn: rect, transform: nil)
print("Dot- index: \(index) rect: \(rect)")
}
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
func scroll(toPage index: Int, progress: CGFloat) { func scroll(toPage index: Int, screenTransitionProgress: CGFloat) {
var scrollProgress = max(0, progress) guard screenTransitionProgress != 0 else { return }
scrollProgress = min(progress, 1) var scrollProgress = max(0, screenTransitionProgress)
scrollProgress = min(screenTransitionProgress, 1)
print("[Page] scroll to \(index) progress: \(scrollProgress)")
let targetDot = dots[index]
let previousDot = dots[index == 0 ? 0 : index - 1]
//Scale
// let scaleDelta = (kDotSize.width - kIndicatorSize.width) * scrollProgress
// previousDot.frame.size = .init(width: kIndicatorSize.width + scaleDelta, height: kIndicatorSize.height + scaleDelta)
// print("[Frame] prev dot frame: \(previousDot.frame)")
let delta = targetDot.frame.origin.x - previousDot.frame.origin.x
indicator.frame.origin.x = previousDot.frame.origin.x + delta * scrollProgress
} }
} }
private extension OnboardingPageControl { private extension OnboardingPageControl {
func prepareDots() { func prepareDots() {
for _ in 0..<totalPagesCount { for index in 0..<totalPagesCount {
let dot = CAShapeLayer() let dot = CAShapeLayer()
dot.fillColor = UIColor.blue.cgColor let cgIndex = CGFloat(index)
let space = index == 0 ? 0 : kSpacePerDot
let size = index == 0 ? kIndicatorSize : kDotSize
let rect: CGRect
if index == 0 {
rect = .init(origin: .init(x: 0, y: (frame.height - kIndicatorSize.height) / 2), size: size)
}
else {
rect = .init(origin: .init(x: cgIndex * (size.width + space), y: 0), size: size)
}
dot.frame = rect
dot.backgroundColor = UIColor.blue.cgColor
dot.cornerRadius = kDotSize.height / 2
layer.addSublayer(dot) layer.addSublayer(dot)
dots.append(dot) dots.append(dot)
} }
} }
func prepareIndicator() { func prepareIndicator() {
indicator.fillColor = UIColor.red.cgColor indicator.backgroundColor = UIColor.red.cgColor
indicator.path = UIBezierPath(roundedRect: .init(origin: .zero, size: kDotSize), indicator.frame = .init(origin: .zero, size: kDotSize)
cornerRadius: kDotSize.height / 2).cgPath indicator.cornerRadius = kIndicatorSize.height / 2
indicator.frame = .init(origin: .init(x: 0, y: (frame.height - kIndicatorSize.height) / 2),
size: kIndicatorSize)
layer.addSublayer(indicator) layer.addSublayer(indicator)
} }
} }
...@@ -46,14 +46,16 @@ enum OnboardingControllerType { ...@@ -46,14 +46,16 @@ enum OnboardingControllerType {
} }
} }
class OnboardingPageController: UIPageViewController { class OnboardingPageController: UIPageViewController, UIScrollViewDelegate {
private let coordinator: AppCoordinator private let coordinator: AppCoordinator
private let control = OnboardingPageControl(totalPagesCount: 3)
private let pageControl = UIPageControl() private let pageControl = UIPageControl()
private let closeButton = UIButton() private let closeButton = UIButton()
private var pages = [UIViewController]() private var pages = [UIViewController]()
private let skipButton = SelfSizingButton() private let skipButton = SelfSizingButton()
private let nextButton = UIButton() private let nextButton = UIButton()
private let doneButton = UIButton() private let doneButton = UIButton()
private var currentPageIndex = 0
init(coordinator: AppCoordinator) { init(coordinator: AppCoordinator) {
self.coordinator = coordinator self.coordinator = coordinator
...@@ -73,10 +75,13 @@ class OnboardingPageController: UIPageViewController { ...@@ -73,10 +75,13 @@ class OnboardingPageController: UIPageViewController {
super.viewDidLoad() super.viewDidLoad()
#if DEBUG #if DEBUG
let control = OnboardingPageControl(totalPagesCount: 5) view.addSubview(control)
view.addSubview(control) control.snp.makeConstraints { make in
control.frame.origin.x = 100 make.top.equalToSuperview().inset(80)
control.frame.origin.y = 80 make.left.equalToSuperview().inset(100)
make.width.equalTo(47)
make.height.equalTo(9)
}
#else #else
fatalError("Remove in release") fatalError("Remove in release")
#endif #endif
...@@ -88,6 +93,7 @@ class OnboardingPageController: UIPageViewController { ...@@ -88,6 +93,7 @@ class OnboardingPageController: UIPageViewController {
prepareNextButton() prepareNextButton()
prepareDoneButton() prepareDoneButton()
updateUI() updateUI()
control.sizeToFit()
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
...@@ -112,12 +118,13 @@ class OnboardingPageController: UIPageViewController { ...@@ -112,12 +118,13 @@ class OnboardingPageController: UIPageViewController {
let currentViewController = viewControllers?.first, let currentViewController = viewControllers?.first,
let currentIndex = pages.firstIndex(of: currentViewController) let currentIndex = pages.firstIndex(of: currentViewController)
else { else {
return return
} }
let nextIndex = currentIndex + 1 let nextIndex = currentIndex + 1
guard nextIndex < pages.count else { return } guard nextIndex < pages.count else { return }
setViewControllers([pages[nextIndex]], direction: .forward, animated: true) {[weak self] _ in setViewControllers([pages[nextIndex]], direction: .forward, animated: true) {[weak self] _ in
self?.currentPageIndex = nextIndex
self?.pageControl.currentPage = nextIndex self?.pageControl.currentPage = nextIndex
self?.showDoneIfNeeded(for: nextIndex) self?.showDoneIfNeeded(for: nextIndex)
} }
...@@ -162,6 +169,14 @@ private extension OnboardingPageController { ...@@ -162,6 +169,14 @@ private extension OnboardingPageController {
dataSource = self dataSource = self
delegate = self delegate = self
setViewControllers([pages[0]], direction: .forward, animated: false) setViewControllers([pages[0]], direction: .forward, animated: false)
//Try to find scroll view
for subview in view.subviews {
if subview.isKind(of: UIScrollView.self) {
let scrollView = subview as? UIScrollView
scrollView?.delegate = self
}
}
} }
func preparePageControl() { func preparePageControl() {
...@@ -249,6 +264,22 @@ private extension OnboardingPageController { ...@@ -249,6 +264,22 @@ private extension OnboardingPageController {
} }
} }
//MARK:- UIScrollView Delegate
extension OnboardingPageController {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let pageWidth = scrollView.contentSize.width / CGFloat(pages.count)
let progress = (scrollView.contentOffset.x - pageWidth) / pageWidth
print("progress: \(progress)")
let nextPageIndex = progress < 0 ? currentPageIndex - 1 : currentPageIndex + 1
if nextPageIndex > pages.count - 1 || nextPageIndex < 0 {
return
}
control.scroll(toPage: nextPageIndex, screenTransitionProgress: abs(progress))
}
}
//MARK:- UIPageViewController Data Source //MARK:- UIPageViewController Data Source
extension OnboardingPageController: UIPageViewControllerDataSource { extension OnboardingPageController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
...@@ -281,6 +312,7 @@ extension OnboardingPageController: UIPageViewControllerDelegate { ...@@ -281,6 +312,7 @@ extension OnboardingPageController: UIPageViewControllerDelegate {
} }
pageControl.currentPage = currentPageIndex pageControl.currentPage = currentPageIndex
self.currentPageIndex = currentPageIndex
showDoneIfNeeded(for: currentPageIndex) showDoneIfNeeded(for: currentPageIndex)
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment