9

iOS 上的 PDFKit 是否公开了 PDFView 的底层 UIScrollView 或者是否有任何其他方法可以直接检测用户是否滚动了 PDFView?

我的用例是在滚动文档时隐藏导航栏,因此作为一种解决方法,我已将自己的平移手势识别器添加到 PDFView 的父级中,并且我在gestureRecognizerShouldBegin 中进行隐藏并始终返回false,但我希望有更多类似于 UIScrollViewDelegate我在文档中丢失了。

4

5 回答 5

5

尝试这个,

NotificationCenter.default.addObserver(self, selector: #selector(handlePageChange(notification:)), name: Notification.Name.PDFViewPageChanged, object: nil)

@objc private func handlePageChange(notification: Notification)
{
    print("Page changed")
}
于 2018-03-13T17:09:30.023 回答
2

我这样做是为了检测 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
            }
        }
    }
} 
于 2019-12-17T14:51:04.283 回答
2

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];
    }
}
于 2020-02-19T06:42:08.607 回答
1

决定其他人尚未完成的解决方案。与观察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
    }
}
于 2021-12-07T20:38:52.223 回答
0

尝试这个!

(pdfView.subviews[0] as? UIScrollView)?.delegate = self

并观察滚动视图委托

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if scrollView.contentOffset.y > 0 {
        /// ...
    } else {
        /// ...
    }
}
于 2022-02-25T03:35:09.957 回答