iOS 上的 PDFKit 是否公开了 PDFView 的底层 UIScrollView 或者是否有任何其他方法可以直接检测用户是否滚动了 PDFView?
我的用例是在滚动文档时隐藏导航栏,因此作为一种解决方法,我已将自己的平移手势识别器添加到 PDFView 的父级中,并且我在gestureRecognizerShouldBegin 中进行隐藏并始终返回false,但我希望有更多类似于 UIScrollViewDelegate我在文档中丢失了。
iOS 上的 PDFKit 是否公开了 PDFView 的底层 UIScrollView 或者是否有任何其他方法可以直接检测用户是否滚动了 PDFView?
我的用例是在滚动文档时隐藏导航栏,因此作为一种解决方法,我已将自己的平移手势识别器添加到 PDFView 的父级中,并且我在gestureRecognizerShouldBegin 中进行隐藏并始终返回false,但我希望有更多类似于 UIScrollViewDelegate我在文档中丢失了。
尝试这个,
NotificationCenter.default.addObserver(self, selector: #selector(handlePageChange(notification:)), name: Notification.Name.PDFViewPageChanged, object: nil)
@objc private func handlePageChange(notification: Notification)
{
print("Page changed")
}
我这样做是为了检测 pdfView 上的缩放和平移,以将这些手势复制到第二个 pdfView,它在这里工作得非常好。通过我在这里找到的 PanDirectionGestureRecognizer 获得了一些帮助来检测垂直和水平平移:stackoverflow.com/a/55635482/558112
class Document: UIViewController, UIScrollViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
// Subscribe to notifications.
NotificationCenter.default.addObserver(self, selector: #selector(onPageZoomAndPan), name: .PDFViewScaleChanged, object: pdfView
// get the scrollView in pdfView and attach gesture recognizers
outerLoop: for subView in pdfView.subviews {
for view in subView.subviews {
if let scrollView = view as? UIScrollView {
let xScrollViewPanGesture = PanDirectionGestureRecognizer(direction: .horizontal, target: self, action: #selector(onPageZoomAndPan))
xScrollViewPanGesture.delegate = self
scrollView.addGestureRecognizer(xScrollViewPanGesture)
let yScrollViewPanGesture = PanDirectionGestureRecognizer(direction: .vertical, target: self, action: #selector(onPageZoomAndPan))
yScrollViewPanGesture.delegate = self
scrollView.addGestureRecognizer(yScrollViewPanGesture)
break outerLoop
}
}
}
}
// MARK: - UIScrollViewDelegate
@objc private func onPageZoomAndPan() {
let rect = pdfView.convert(pdfView.bounds, to: pdfView.currentPage!)
pdfViewSecondScreen.scaleFactor = pdfView.scaleFactor
pdfViewSecondScreen.go(to: rect, on: pdfView.currentPage!)
}
}
enum PanDirection {
case vertical
case horizontal
}
// UIKit.UIGestureRecognizerSubclass
import UIKit.UIGestureRecognizerSubclass
class PanDirectionGestureRecognizer: UIPanGestureRecognizer {
let direction : PanDirection
init(direction: PanDirection, target: AnyObject, action: Selector) {
self.direction = direction
super.init(target: target, action: action)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
super.touchesMoved(touches, with: event)
if state == .began {
let vel = velocity(in: self.view!)
switch direction {
case .horizontal where abs(vel.y) > abs(vel.x):
state = .cancelled
case .vertical where abs(vel.x) > abs(vel.y):
state = .cancelled
default:
break
}
}
}
}
iOS 上的 PDFKit 是否公开了 PDFView 的底层 UIScrollView
不,但希望苹果将来会添加这个。记得UIWebView原来没有,后来加的。
或者有没有其他方法可以直接检测到用户滚动了 PDFView
不,看起来PDFViewDelegate
这个地址提供的通知都没有。
我正在从 UIWebView 迁移到 PDFView 并且正在使用scrollViewDidScroll
一堆东西,所以我不想仅仅依靠添加一个平移手势识别器。从@Matthijs 的答案构建,我在 PDFView 中找到 UIScrollView,使我的类成为它的委托,然后将任何事件传递回滚动视图(在我的类成为委托之前它是它自己的委托),以便它可以响应它们, 也。使用 UIWebView,这最后一步不是必需的,但使用 PDFView,缩放和可能的其他功能将无法正常工作。
我将覆盖所有记录在案的委托方法,以减少如果 Apple 更改 PDFView 的内部功能而中断的可能性。但是,我必须检查respondsToSelector
每个方法,因为原始滚动视图委托当前并未实现所有这些方法。
- (void)viewDidLoad {
// create the PDFView and find its inner scrollView
self.pdfView = [[PDFView alloc] init];
for (UIView *subview in self.pdfView.subviews) {
if ([subview isKindOfClass:[UIScrollView class]]) {
self.scrollView = (UIScrollView *)subview;
} else {
for (UIView *subsubview in subview.subviews) {
if ([subsubview isKindOfClass:[UIScrollView class]]) {
self.scrollView = (UIScrollView *)subsubview;
}
}
}
}
}
- (void)loadPDFDocument:(NSString *)URL {
// load a document, then become the delegate for the scrollView (we have to do that after loading the document)
PDFDocument *document = [[PDFDocument alloc] initWithURL:URL];
self.pdfView.document = document;
self.scrollView.delegate = self;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// *** respond to scroll events here ***
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidScroll:)]) {
[scrollViewDelegate scrollViewDidScroll:scrollView];
}
}
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewWillBeginDragging:)]) {
[scrollViewDelegate scrollViewWillBeginDragging:scrollView];
}
}
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewWillEndDragging:withVelocity:targetContentOffset:)]) {
[scrollViewDelegate scrollViewWillEndDragging:scrollView withVelocity:velocity targetContentOffset:targetContentOffset];
}
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidEndDragging:willDecelerate:)]) {
[scrollViewDelegate scrollViewDidEndDragging:scrollView willDecelerate:decelerate];
}
}
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewShouldScrollToTop:)]) {
return [scrollViewDelegate scrollViewShouldScrollToTop:scrollView];
}
return TRUE;
}
- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidScrollToTop:)]) {
[scrollViewDelegate scrollViewDidScrollToTop:scrollView];
}
}
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewWillBeginDecelerating:)]) {
[scrollViewDelegate scrollViewWillBeginDecelerating:scrollView];
}
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidEndDecelerating:)]) {
[scrollViewDelegate scrollViewDidEndDecelerating:scrollView];
}
}
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(viewForZoomingInScrollView:)]) {
return [scrollViewDelegate viewForZoomingInScrollView:scrollView];
}
return nil;
}
- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewWillBeginZooming:withView:)]) {
[scrollViewDelegate scrollViewWillBeginZooming:scrollView withView:view];
}
}
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(CGFloat)scale {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidEndZooming:withView:atScale:)]) {
[scrollViewDelegate scrollViewDidEndZooming:scrollView withView:view atScale:scale];
}
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidZoom:)]) {
[scrollViewDelegate scrollViewDidZoom:scrollView];
}
}
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidEndScrollingAnimation:)]) {
[scrollViewDelegate scrollViewDidEndScrollingAnimation:scrollView];
}
}
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView {
UIScrollView <UIScrollViewDelegate> *scrollViewDelegate = (UIScrollView <UIScrollViewDelegate> *)self.scrollView;
if ([scrollViewDelegate respondsToSelector:@selector(scrollViewDidChangeAdjustedContentInset:)]) {
[scrollViewDelegate scrollViewDidChangeAdjustedContentInset:scrollView];
}
}
决定其他人尚未完成的解决方案。与观察contentOffset
底层属性的关键值一起去UIScrollView
。
每次滚动偏移更改时,您都可以使用此扩展程序运行回调。
var observation = pdfView.onScrollOffsetChanged { scroll in
print("PDFView scrolled to \(scroll.contentOffset).")
}
扩展名
extension PDFView {
func onScrollOffsetChange(handler: @escaping (UIScrollView) -> Void) -> NSKeyValueObservation? {
detectScrollView()?.observe(\.contentOffset) { scroll, _ in
handler(scroll)
}
}
private func detectScrollView() -> UIScrollView? {
for view in subviews {
if let scroll = view as? UIScrollView {
return scroll
} else {
for subview in view.subviews {
if let scroll = subview as? UIScrollView {
return scroll
}
}
}
}
print("Unable to find a scrollView subview on a PDFView.")
return nil
}
}
尝试这个!
(pdfView.subviews[0] as? UIScrollView)?.delegate = self
并观察滚动视图委托
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
/// ...
} else {
/// ...
}
}