ScrollViewObserver

无需设置代理即可观察任何 UIScrollView

这是什么?

这个小库提供了一些实用类和辅助方法,用于观察 UIScrollView 中的滚动偏移量变化,而无需设置代理。

此外,还有一些辅助方法可以在跨越特定(动态确定)阈值时自动触发回调,并根据滚动偏移量自动显示/隐藏视图。

观察 Content Offset(内容偏移)

便捷方法

您可以调用一个便捷辅助方法来快速开始观察滚动偏移量变化:UIScrollView.observeContentOffsetChanges()

此方法返回一个 ScrollViewObserverCancellable,您可以使用它来停止观察。如果您永远不会停止观察,您可以简单地忽略返回值。

警告:不要在回调闭包中强引用滚动视图,否则会导致循环引用。

示例 1

// prints content offset changes for the next 10 seconds
let cancellable = scrollView.observeContentOffsetChanges { scrollView in
	print(scrollView.contentOffset) 
}
DispatchQueue.main.asyncAfter(.now() + 10) {
	cancellable.cancel()
}

示例 2

// there's also a version that doesn't take a scroll view as parameter
scrollView.observeContentOffsetChanges { [weak self] in
	self?.doSomethingWhenWeScroll()
}

ScrollViewObserver

该便捷方法封装并跟踪 ScrollViewObserver。您也可以自己跟踪。

class UIViewController {
	var observer: ScrollViewObserver!
	
	func viewDidLoad() {
		super.viewDidLoad()
		
		// here we manually track an observer object. We need to hold on to it, because
		// when it is deallocated, the observing will stop
		observer = ScrollViewObserver(scrollView: scrollView) { scrollView _ 
			print(scrollView.contentOffset)
		}
	}
}

监控偏移阈值

还有一个辅助方法可以跟踪何时跨越特定阈值,并且仅在跨越阈值时触发回调。 例如,这可以用于切换...

便捷方法

UIScrollView.monitorOffsetTreshold()

此方法返回一个 ScrollViewObserverCancellable,您可以使用它来停止观察。如果您永远不会停止观察,您可以简单地忽略返回值。

警告:不要在回调闭包中强引用滚动视图,否则会导致循环引用。

示例

// This prints "A" if we scrolled to the first half of the scroll view and "B" in the second half.

let cancellable = scrollView.monitorOffsetTreshold(tresholdProvider: { scrollView in
		return scrollView.contentSize.height * 0.5
	}, callback: { isOverTreshold in 
		if isOverTreshold {
			print("A")
		} else {
			print("B"")
		}
	})

您还可以提供自定义: - contentOffsetProvider,它告诉监视器滚动视图的位置。通常,默认实现是合适的。 - 自定义 visibilityProvider,它告诉监视器是否跨越了阈值。 默认实现执行 offset > treshold,通常是合适的。

ScrollViewOffsetMonitor

便捷方法封装并跟踪一个 ScrollViewOffsetMonitor 对象。您也可以自己跟踪

class UIViewController {
	var monitor: ScrollViewOffsetMonitor!

	func viewDidLoad() {
		super.viewDidLoad()

		// here we manually track a monitor object. We need to hold on to it, because
		// 	when it is deallocated, the observing will stop
		monitor = ScrollViewOffsetMonitor(scrollView: scrollView,tresholdProvider: { scrollView in 
			return scrollView.contentSize.height * 0.5
		}, callback: { isOverTreshold in 
			if isOverTreshold {
				print("A")
			} else {
				print("B"")
			}
		})
	}
}

根据滚动 ContentOffset 自动隐藏/显示视图

有一个辅助类(和便捷方法)可以根据滚动视图中是否跨越了特定阈值,自动隐藏/显示视图(通过设置 alpha)。

例如,这可以用于在 header view 可见时隐藏 label。

便捷方法

这些方法返回一个 ScrollViewObserverCancellable,您可以使用它来停止观察。如果您永远不会停止观察,您可以简单地忽略返回值。

警告:不要在回调闭包中强引用滚动视图,否则会导致循环引用。

示例


// this will automatically hide the `someLabel` when we haven't scrolled past
// the top of `someOtherView`
let cancellable = scrollView.toggleVisibility(
						of: someLabel,
						style: .showWhenPastTreshold,
						whenScrollingPast: someOtherView,
						edge: .top)
						

// this will automatically  hide `someLabel` when we scrolled past the bottom of `someOtherView`
scrollView.toggleVisibility(of: someLabel, style: .hideWhenPastTreshold, whenScrollingPast: someOtherView)

// this will automaticaly hide `someLabel` when we scrolled past row 1 of section 0
tableView.toggleVisibility(of: someLabel, whenScrollingPast: IndexPath(row: 1, section: 0)

// this will automatically show `someLabel` when we scrolled past row 1 of section 0
let cancelleble = collectionView.toggleVisibility(of: someLabel, style: .hideWhenPastTreshold, whenScrollingPast: IndexPath(row: 1, section: 0)

ScrollViewVisibilityToggler

便捷方法封装并跟踪一个 ScrollViewVisibilityToggler 对象。您也可以自己跟踪

class UIViewController {
	var toggler: ScrollViewVisibilityToggler!

	func viewDidLoad() {
		super.viewDidLoad()

		// here we manually track a toggler object. We need to hold on to it, because
		// 	when it is deallocated, the observing will stop
		toggler = ScrollViewVisibilityToggler(scrollView: scrollView, viewToMonitor: someOtherView, viewToToggle: someLabel)
	}
}

UINavigationItem 标题

UINavigationItem 上有一些辅助方法,可以在滚动超过另一个视图时自动显示自定义 titleView。 还有一个辅助方法可以直接显示自定义字符串。

示例

// this will automatically show mylabel when scrolling past the the title label in our custom header
navigationItem.setCustomTitleView(myLabel, whenScrollingPast: myCustomHeaderView.titleLabel, in: tableView)

// this will automatically show "My Custom Title" when scrolling past the the title label in our custom header
navigationItem.showCustomTitle("My Custom Title", whenScrollingPasth myCustomheaderView.titleLabel, in: scrollView)