Skip to content
Snippets Groups Projects

Implement animated scroll tab alternating

Merged Bruno Muniz requested to merge search-tabs-scroll into development
18 files
+ 460
844
Compare changes
  • Side-by-side
  • Inline
Files
18
import UIKit
import UIKit
import Theme
import Theme
import Shared
import Shared
 
import Combine
import DependencyInjection
import DependencyInjection
public final class SearchContainerController: UIViewController {
public final class SearchContainerController: UIViewController {
@@ -8,8 +9,16 @@ public final class SearchContainerController: UIViewController {
@@ -8,8 +9,16 @@ public final class SearchContainerController: UIViewController {
lazy private var screenView = SearchContainerView()
lazy private var screenView = SearchContainerView()
 
private var cancellables = Set<AnyCancellable>()
 
private let qrController = SearchQRController()
 
private let emailController = SearchEmailController()
 
private let phoneController = SearchPhoneController()
 
private let usernameController = SearchUsernameController()
 
public override func loadView() {
public override func loadView() {
view = screenView
view = screenView
 
screenView.scrollView.delegate = self
 
embedControllers()
}
}
public override func viewWillAppear(_ animated: Bool) {
public override func viewWillAppear(_ animated: Bool) {
@@ -24,6 +33,7 @@ public final class SearchContainerController: UIViewController {
@@ -24,6 +33,7 @@ public final class SearchContainerController: UIViewController {
public override func viewDidLoad() {
public override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
setupNavigationBar()
setupNavigationBar()
 
setupBindings()
}
}
private func setupNavigationBar() {
private func setupNavigationBar() {
@@ -42,7 +52,107 @@ public final class SearchContainerController: UIViewController {
@@ -42,7 +52,107 @@ public final class SearchContainerController: UIViewController {
)
)
}
}
 
private func setupBindings() {
 
screenView.segmentedControl
 
.actionPublisher
 
.receive(on: DispatchQueue.main)
 
.sink { [unowned self] in
 
let page = CGFloat($0.rawValue)
 
let point: CGPoint = CGPoint(x: screenView.frame.width * page, y: 0.0)
 
screenView.scrollView.setContentOffset(point, animated: true)
 
}.store(in: &cancellables)
 
}
 
@objc private func didTapBack() {
@objc private func didTapBack() {
navigationController?.popViewController(animated: true)
navigationController?.popViewController(animated: true)
}
}
 
 
private func embedControllers() {
 
addChild(qrController)
 
addChild(emailController)
 
addChild(phoneController)
 
addChild(usernameController)
 
 
screenView.scrollView.addSubview(qrController.view)
 
screenView.scrollView.addSubview(emailController.view)
 
screenView.scrollView.addSubview(phoneController.view)
 
screenView.scrollView.addSubview(usernameController.view)
 
 
usernameController.view.snp.makeConstraints {
 
$0.top.equalTo(screenView.segmentedControl.snp.bottom)
 
$0.width.equalTo(screenView)
 
$0.bottom.equalTo(screenView)
 
$0.left.equalToSuperview()
 
$0.right.equalTo(emailController.view.snp.left)
 
}
 
 
emailController.view.snp.makeConstraints {
 
$0.top.equalTo(screenView.segmentedControl.snp.bottom)
 
$0.width.equalTo(screenView)
 
$0.bottom.equalTo(screenView)
 
$0.right.equalTo(phoneController.view.snp.left)
 
}
 
 
phoneController.view.snp.makeConstraints {
 
$0.top.equalTo(screenView.segmentedControl.snp.bottom)
 
$0.width.equalTo(screenView)
 
$0.bottom.equalTo(screenView)
 
$0.right.equalTo(qrController.view.snp.left)
 
}
 
 
qrController.view.snp.makeConstraints {
 
$0.top.equalTo(screenView.segmentedControl.snp.bottom)
 
$0.width.equalTo(screenView)
 
$0.bottom.equalTo(screenView)
 
}
 
 
qrController.didMove(toParent: self)
 
emailController.didMove(toParent: self)
 
phoneController.didMove(toParent: self)
 
usernameController.didMove(toParent: self)
 
}
 
}
 
 
extension SearchContainerController: UIScrollViewDelegate {
 
public func scrollViewDidScroll(_ scrollView: UIScrollView) {
 
let pageOffset = scrollView.contentOffset.x / view.frame.width
 
scrollSegmentedControlTrack(using: pageOffset)
 
updateSegmentedControlButtonsColor(using: pageOffset)
 
}
 
 
private func scrollSegmentedControlTrack(using pageOffset: CGFloat) {
 
let amountOfTabs = 4.0
 
let tabWidth = screenView.bounds.width / amountOfTabs
 
 
if let leftConstraint = screenView.segmentedControl.leftConstraint {
 
leftConstraint.update(offset: pageOffset * tabWidth)
 
}
 
}
 
 
private func updateSegmentedControlButtonsColor(using pageOffset: CGFloat) {
 
let qrRate = highlightRateFor(page: 3, offset: pageOffset)
 
let emailRate = highlightRateFor(page: 1, offset: pageOffset)
 
let phoneRate = highlightRateFor(page: 2, offset: pageOffset)
 
let usernameRate = highlightRateFor(page: 0, offset: pageOffset)
 
 
screenView.segmentedControl.qrCodeButton.updateHighlighting(rate: qrRate)
 
screenView.segmentedControl.emailButton.updateHighlighting(rate: emailRate)
 
screenView.segmentedControl.phoneButton.updateHighlighting(rate: phoneRate)
 
screenView.segmentedControl.usernameButton.updateHighlighting(rate: usernameRate)
 
}
 
 
private func highlightRateFor(page: CGFloat, offset: CGFloat) -> CGFloat {
 
let lowerBound = page - 1
 
let upperBound = page + 1
 
 
if offset > lowerBound && offset < upperBound {
 
if (offset - lowerBound) > 1 {
 
return 1 - (offset - page)
 
} else {
 
return offset - lowerBound
 
}
 
} else {
 
return 0
 
}
 
}
}
}
Loading