Skip to content

Instantly share code, notes, and snippets.

@delannoyk
Created February 4, 2022 14:18
Show Gist options
  • Save delannoyk/705b9830ad8677c737bc00f7dac9e139 to your computer and use it in GitHub Desktop.
Save delannoyk/705b9830ad8677c737bc00f7dac9e139 to your computer and use it in GitHub Desktop.
import UIKit
final class ScrollIndicatorBehavior {
// MARK: Properties
var leftInset: CGFloat {
didSet { updateShadowFrame() }
}
var rightInset: CGFloat {
didSet { updateShadowFrame() }
}
var shadowWidth: CGFloat {
didSet { updateShadowFrame() }
}
private let leftShadow: GradientView = {
let view = GradientView()
view.locations = [0, 1]
view.colors = [UIColor.black, UIColor.clear]
view.mode = .linear(.horizontal)
return view
}()
private let rightShadow: GradientView = {
let view = GradientView()
view.locations = [0, 1]
view.colors = [UIColor.clear, UIColor.black]
view.mode = .linear(.horizontal)
return view
}()
// MARK: Initialization
init(containerView: UIView, leftInset: CGFloat = 0, rightInset: CGFloat = 0, shadowWidth: CGFloat = 20) {
self.leftInset = leftInset
self.rightInset = rightInset
self.shadowWidth = shadowWidth
containerView.addSubview(leftShadow)
containerView.addSubview(rightShadow)
}
// MARK: Shadow Management
private func updateShadowFrame() {
guard let containerView = leftShadow.superview else { return }
let size = CGSize(width: shadowWidth, height: containerView.frame.height)
let leftOriginX: CGFloat
let rightOriginX: CGFloat
if let containerView = containerView as? UIScrollView {
leftOriginX = containerView.contentOffset.x + leftInset
rightOriginX = containerView.contentOffset.x + containerView.frame.width - shadowWidth - rightInset
} else {
leftOriginX = leftInset
rightOriginX = containerView.frame.width - shadowWidth - rightInset
}
leftShadow.frame = CGRect(origin: CGPoint(x: leftOriginX, y: 0), size: size)
rightShadow.frame = CGRect(origin: CGPoint(x: rightOriginX, y: 0), size: size)
}
private func setScrollPercentage(_ percentage: CGFloat) {
if percentage.isNaN {
leftShadow.alpha = 0
rightShadow.alpha = 0
} else {
let alpha = max(min(percentage, 1), 0)
leftShadow.alpha = alpha
rightShadow.alpha = 1 - alpha
}
}
// MARK: ScrollViewBehavior
func afterScrolling(_ scrollView: UIScrollView) {
let frameSize = scrollView.frame.size
let contentSize = scrollView.contentSize
guard frameSize.width < contentSize.width else {
setScrollPercentage(.nan)
return
}
let minLeftOffset = -scrollView.contentInset.left
let contentOffset = scrollView.contentOffset
let maxLeftOffset = contentSize.width - frameSize.width
let maxMinDifference = maxLeftOffset - minLeftOffset
guard maxMinDifference != 0 else {
setScrollPercentage(.nan)
return
}
let scrolledPercentage = (contentOffset.x - minLeftOffset) / maxMinDifference
setScrollPercentage(scrolledPercentage)
updateShadowFrame()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment