Imagine we have the following UIScrollView:
- contentSize:
500 x 500
- frame/bounds size:
200 x 200
- contentInsets:
(10, 10, 20, 20)
Calculated contentOffsets:
- Min contentOffset:
- .x:
-contentInset.left (-10)
- .y:
-contentInset.top (-10)
- Max contentOffset
- .x:
contentSize.width - bounds.width + contentInset.right (320)
- .y:
contentSize.height - bounds.height + contentInset.bottom (320)
Normally a UIScrollView starts at contentOffset = (0, 0). However, when you add contentInsets, it starts offset by a negative amount. When you scroll the first position into view so that you don't see the contentInset, you'll be at contentOffset = (0,0).
A similar thing happens at the end, where instead of 300 being the max offset, 320 becomes the max.
func minContentOffset(scrollView: UIScrollView) -> CGPoint {
return CGPoint(
x: -scrollView.contentInset.left,
y: -scrollView.contentInset.top)
}
func maxContentOffset(scrollView: UIScrollView) -> CGPoint {
return CGPoint(
x: scrollView.contentSize.width - scrollView.bounds.width + scrollView.contentInset.right,
y: scrollView.contentSize.height - scrollView.bounds.height + scrollView.contentInset.bottom)
}
You could then create a function that uses both of those to determine if a scroll view is scrollable:
func canVerticallyScroll(scrollView: UIScrollView) -> Bool {
let scrollableHeight = maxContentOffset(scrollView: scrollView).y
- minContentOffset(scrollView: scrollView).y
let viewableHeight = scrollView.bounds.height
return viewableHeight < scrollableHeight
}
Or as an extension:
extension UIScrollView {
var minContentOffset: CGPoint {
return CGPoint(
x: -contentInset.left,
y: -contentInset.top)
}
var maxContentOffset: CGPoint {
return CGPoint(
x: contentSize.width - bounds.width + contentInset.right,
y: contentSize.height - bounds.height + contentInset.bottom)
}
func scrollToMinContentOffset(animated: Bool) {
setContentOffset(minContentOffset, animated: animated)
}
func scrollToMaxContentOffset(animated: Bool) {
setContentOffset(maxContentOffset, animated: animated)
}
}