Определить, что PDFView прокручивал
Предоставляет ли PDFKit на iOS доступ к базовому UIScrollView для PDFView или есть какой-либо другой способ непосредственно определить, что пользователь прокрутил PDFView?
Мой вариант использования - скрыть панель навигации, когда документ прокручивается, так что в качестве обходного пути я добавил свой собственный распознаватель жестов панорамирования в родительский элемент PDFView, и я скрываю в gestRecognizerShouldBegin и всегда возвращаю false, но я ожидаю, что есть что-то более похожее на UIScrollViewDelegate что я скучаю по документам.
5 ответов
Попробуй это,
NotificationCenter.default.addObserver(self, selector: #selector(handlePageChange(notification:)), name: Notification.Name.PDFViewPageChanged, object: nil)
@objc private func handlePageChange(notification: Notification)
{
print("Page changed")
}
Предоставляет ли PDFKit на iOS базовый UIScrollView PDFView
Нет, но, надеюсь, Apple добавит это в будущем. Я помню, что у UIWebView его изначально не было, и он был добавлен позже.
или есть ли другой способ напрямую определить, что пользователь прокрутил PDFView
Нет, похоже, ни одно из уведомлений, предоставленных PDFViewDelegate
обратиться к этому.
Я перехожу с UIWebView на PDFView и использую scrollViewDidScroll
для множества вещей, поэтому я не хотел полагаться только на добавление распознавателя жестов панорамирования. Основываясь на ответе @Matthijs, я нахожу UIScrollView внутри PDFView, делаю свой класс своим делегатом, а затем передаю любые события обратно в представление прокрутки (которое было его собственным делегатом до того, как мой класс стал делегатом), чтобы он мог отвечать на них, слишком. В 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];
}
}
Я сделал это, чтобы обнаружить масштабирование и панорамирование в pdfView, чтобы скопировать эти жесты во второй pdfView, и здесь он отлично работает. Получил некоторую помощь в обнаружении вертикального и горизонтального панорамирования с помощью PanDirectionGestureRecognizer, который я нашел здесь: /questions/8461757/uipangesturerecognizer-tolko-vertikalnyij-ili-gorizontalnyij/49438038#49438038
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
}
}
}
}
Решил решение, которое другие еще не сделали. Пошел с ключевым значением, наблюдая за
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
и наблюдайте за делегатом scrollview
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.y > 0 {
/// ...
} else {
/// ...
}
}