Commit d0338d27 by Orkhan Alikhanov

Made swipe transition interactive for TabsController

parent 9aec4010
......@@ -110,9 +110,8 @@ open class TabsController: TransitionController {
@IBInspectable
public let tabBar = TabBar()
/// A Boolean that indicates if the swipe feature is enabled..
open var isSwipeEnabled = false {
/// A Boolean that controls if the swipe feature is enabled.
open var isSwipeEnabled = true {
didSet {
guard isSwipeEnabled else {
removeSwipeGesture()
......@@ -149,6 +148,18 @@ open class TabsController: TransitionController {
}
/**
A UIPanGestureRecognizer property internally used for the interactive
swipe.
*/
public private(set) var interactiveSwipeGesture: UIPanGestureRecognizer?
/**
A private integer for storing index of target view controller
during interactive transition.
*/
private var targetIndex = -1
/**
An initializer that initializes the object with a NSCoder object.
- Parameter aDecoder: A NSCoder instance.
*/
......@@ -212,32 +223,19 @@ fileprivate extension TabsController {
return
}
var isAuto = false
switch motionTransitionType {
case .auto:
switch viewController.motionTransitionType {
case .auto:
isAuto = true
MotionTransition.shared.setAnimationForNextTransition(fvcIndex < tvcIndex ? .slide(direction: .left) : .slide(direction: .right))
default:break
}
default:break
if case .auto = motionTransitionType, case .auto = viewController.motionTransitionType {
MotionTransition.shared.setAnimationForNextTransition(fvcIndex < tvcIndex ? .slide(direction: .left) : .slide(direction: .right))
}
if isTriggeredByUserInteraction {
delegate?.tabsController?(tabsController: self, willSelect: viewController)
}
super.transition(to: viewController) { [weak self, viewController = viewController, completion = completion] (isFinishing) in
super.transition(to: viewController) { [weak self] (isFinishing) in
guard let `self` = self else {
return
}
if isAuto {
MotionTransition.shared.setAnimationForNextTransition(.auto)
}
completion?(isFinishing)
if isTriggeredByUserInteraction {
......@@ -279,37 +277,82 @@ fileprivate extension TabsController {
tabBar.tabItems = tabItems
tabBar.selectedTabItem = tabItems[selectedIndex]
}
}
private extension TabsController {
/**
A target method contolling interactive swipe transition based on
gesture recognizer.
- Parameter _ gesture: A UIPanGestureRecognizer.
*/
@objc
func handleTransitionPan(_ gesture: UIPanGestureRecognizer) {
let translationX = gesture.translation(in: nil).x
let velocityX = gesture.velocity(in: nil).x
switch gesture.state {
case .began, .changed:
let isSlidingLeft = targetIndex == -1 ? velocityX < 0 : translationX < 0
let nextIndex = selectedIndex + (isSlidingLeft ? 1 : -1)
guard nextIndex >= 0, nextIndex < viewControllers.count else {
return
}
if targetIndex != nextIndex {
/// 5 point threshold
guard abs(translationX) > 5 else {
return
}
tabBar.cancelLineTransition(isAnimated: false)
MotionTransition.shared.cancel(isAnimated: false)
if internalSelect(at: nextIndex, isTriggeredByUserInteraction: true, selectTabItem: false) {
tabBar.startLineTransition(for: nextIndex, duration: 0.35)
targetIndex = nextIndex
}
} else {
let progress = abs(translationX / view.bounds.width)
tabBar.updateLineTransition(progress)
MotionTransition.shared.update(Double(progress))
}
default:
let progress = (translationX + velocityX) / view.bounds.width
let isUserHandDirectionLeft = progress < 0
let isTargetHandDirectionLeft = targetIndex > selectedIndex
if isUserHandDirectionLeft == isTargetHandDirectionLeft && abs(progress) > 0.5 {
tabBar.finishLineTransition()
MotionTransition.shared.finish()
} else {
tabBar.cancelLineTransition()
MotionTransition.shared.cancel()
}
targetIndex = -1
}
}
/// Prepare Swipe Gesture.
/// Prepares interactiveSwipeGesture.
func prepareSwipeGesture() {
removeSwipeGesture()
let swipeRight = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeGesture(gesture:)))
swipeRight.direction = .right
view.addGestureRecognizer(swipeRight)
guard nil == interactiveSwipeGesture else {
return
}
let swipeLeft = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipeGesture(gesture:)))
swipeLeft.direction = .left
view.addGestureRecognizer(swipeLeft)
interactiveSwipeGesture = UIPanGestureRecognizer(target: self, action: #selector(handleTransitionPan))
container.addGestureRecognizer(interactiveSwipeGesture!)
}
}
fileprivate extension TabsController {
/// Remove Swipe Gesture.
/// Removes interactiveSwipeGesture.
func removeSwipeGesture() {
guard let v = view.gestureRecognizers else {
guard let v = interactiveSwipeGesture else {
return
}
for gesture in v {
guard let recognizer = gesture as? UISwipeGestureRecognizer else {
continue
}
if .left == recognizer.direction || .right == recognizer.direction {
view.removeGestureRecognizer(recognizer)
}
}
container.removeGestureRecognizer(v)
interactiveSwipeGesture = nil
}
}
......@@ -363,30 +406,6 @@ fileprivate extension TabsController {
}
}
fileprivate extension TabsController {
/**
Handles the swipe gesture.
- Parameter gesture: A UIGestureRecognizer.
*/
@objc
func handleSwipeGesture(gesture: UIGestureRecognizer) {
if let swipeGesture = gesture as? UISwipeGestureRecognizer {
switch swipeGesture.direction {
case .right:
guard (selectedIndex - 1) >= 0 else { return }
internalSelect(at: selectedIndex - 1, isTriggeredByUserInteraction: true, selectTabItem: true)
case .left:
guard (selectedIndex + 1) < viewControllers.count else { return }
internalSelect(at: selectedIndex + 1, isTriggeredByUserInteraction: true, selectTabItem: true)
default:
break
}
}
}
}
extension TabsController {
/**
Transitions to the view controller that is at the given index.
......@@ -425,6 +444,7 @@ extension TabsController {
}
self?.selectedIndex = index
self?.tabBar.select(at: index)
}
return true
......
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