PDFKit - PdfView won't be RTL without usePageViewController() - ios

I want to display PDF with horizontal, pages from right to left, page by page continuously, and users pinch one page will make all pages the same scale synchronized.
I wrote the codes as below:
if let pdfDocument = PDFDocument(url: pdfUrl) {
pdfView.document = pdfDocument
pdfView.displayMode = .singlePageContinuous
pdfView.displaysRTL = true
pdfView.autoScales = true
pdfView.autoresizesSubviews = true
pdfView.displayDirection = .horizontal
pdfView.displaysPageBreaks = true
pdfView.pageBreakMargins = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
pdfView.maxScaleFactor = 4.0
pdfView.minScaleFactor = pdfView.scaleFactorForSizeToFit
}
But displaysRTL will not work, and default scale will not show whole single page but fit to the PDF page height (page right side will out of screen).
If I add
pdfView.usePageViewController(true)
PDF displayRTL works, and every page will fit screen size by default. BUT this will make PDF not displayed page by page, and zoom in scale will not the same with other pages.
The left page scale is not the same with current zoom in page on the right side. I need them all the same scale if user pinch a page.
Is there any way to fix this problem?
In addition, every page's top-left corner will display an icon, I don't know what is it mean and how to hide it..

I find a way that make it displayRTL manually.
Don't use usePageViewController(true), and just reordering the pages from the PDFDocument.
let doc = PDFDocument()
var getPage = pdfDocument.pageCount - 1
for i in 0..<pdfDocument.pageCount {
guard let pageRef = pdfDocument.page(at: getPage) else { fatalError() }
doc.insert(pageRef, at: i)
getPage -= 1
}
pdfView.document = doc
// Display PDF from last page if Right to Left
if (isPageRTL) {
pdfView.goToLastPage()
}
I found PDFView by Apple will get memory leak and crash if PDF is large in iOS 12 and iOS 13 (iOS 14 seems to be fine). So I have to find other way to display PDF that fit my need.

Related

iOS WKWebView findString not selecting and scrolling

Since iOS 14 WebKit supports findString, but there is no documentation whatsoever yet.
However on the WWDC Sessions Discover WKWebView enhancements they mention that is a basic functionality for "Find on Page", where you can find a string and the WebView will select it and scroll to center it.
It seems very easy to use and to be finding the string as I get a result of matchFound true, but there is no selection and there is no scrolling. Maybe I'm missing something?
This is the code I have tried:
let webView = WKWebView()
// ...
// after loading a website with the desired string on it.
// ...
webView.find("hello world") { result in
print(result.matchFound) // true
}
Update for iOS 16
On iOS 16 we have the new UIFindInteraction API and now it is possible and very easy to do a Find on Page feature and search for a string.
myWebView.isFindInteractionEnabled = true
myWebView.findInteraction?.presentFindNavigator(showingReplace: false)
Important
This is not supported on macOS.
Original Answer
So far I was only able to make it 'kind of working' combining with a bit of JavaScript.
let webView = WKWebView()
webView.select(nil)
webView.find("hello world") { result in
guard result.matchFound else { return }
webView.evaluateJavaScript(
"window.getSelection().getRangeAt(0).getBoundingClientRect().top") { offset, _ in
guard let offset = offset as? CGFloat else { return }
webView.scrollView.scrollRectToVisible(
.init(x: 0,
y: offset + webView.scrollView.contentOffset.y,
width: 100,
height: 100), animated: true)
}
}
Description:
1.
webView.select(nil) to make it first responder.
This is important otherwise when the match is found it won't be selected.
2.
webView.find("my string")
3.
If match is found use JavaScript to get the offset to the selected text.
4.
When receiving the offset scroll to it.

Zoom in to specific coordinates in PDFKit using swift

I am using pdfkit to open pdf file in my app.
I want to zoom in to specific coordinates.
Let say Following is my pdf page and I want to zoom in to specific coordinates when user will click on pencil button.
After clicking on pencil button it should be look like following image.
I've searched a lot but couldn't find any proper solution for that. I don't want to use third party libraries to do that.
I solved this problem by using following code.
let documents = pdfView.document
if let page = documents?.page(at: 0) {
pdfView.scaleFactor = pdfView.scaleFactorForSizeToFit * 2
pdfView.go(to: CGRect(x: 0, y: 0, width: 300, height: 300), on: page)
}
This is the zoom in code to specific coordinates.
There is one more thing that needs attention. You need to turn off
pagination pdfView.usePageViewController(false).

Translating/Scaling UIImageViews based on Screen Size

I have a blank rectangular uiview that dynamically resizes based on the device screen size.
Into the uiview, I programmatically insert uiimageview subviews that I then save CGRect, CGPoint, and CGAffineTransform data to my database.
I can then fetch this data and re-upload and view the uiimageviews I had inserted previously.
All is well if I have the same device screen size, but my issue is trying to adapt these saved data points to other screen sizes so it optically looks good no matter what iOS device you may be on.
I tried storing alongside the other data points, the original height and width of the screen so I can, for example, find the change in width from the original to adjust the original x-coordinate to move more or less points.
let widthPointChange = new.bounds.width - saved.originalSuperviewWidth
let heightPointChange = new.bounds.height - saved.originalSuperviewHeight
newUIImageView.center = CGPoint(x: saved.x + widthPointChange, y: saved.y + heightPointChange)
Is there a better way to do or think about this in terms translating/scaling according to various screen sizes but that stays true to the original? I'm wondering how, for example, Instagram is able to save user generated stories and display them consistently and proportionately across device sizes..
Try this approach!
let view = UIView()
let image = UIImageView()
image.translatesAutoresizingMaskIntoConstraints = false
view.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
view.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
view.addSubview(image)

How do I center a PDFSelection within the overall View?

I'm trying to use PDFKit with Swift in iOS 11. I have a PDFView and a PDFSelection that I would like to scroll to, zoom in to, and center within the overall view. I'm able to scroll to the PDFView's currentSelection with the function scrollSelectionToVisible(_ sender: Any?), but the selection always appear in the upper left of the screen.
How can I reposition the page to make the selection be at the center?
I know a PDFSelection has a bounds(for: PDFPage) function that returns a CGRect, in page space. But I don't know what to do with it beyond that.
What I currently see with after pdfView.scrollSelectionToVisible() (currentSelection in green upper left):
What I'd like to see (currentSelection in center of view):
This:
pdfView.currentSelection = selection
pdfView.scrollSelectionToVisible(nil)
And this:
pdfView.currentSelection = selection
let pdfPage = pdfView.document!.page(at: 0)!
let cgRect = pdfView.currentSelection!.bounds(for: pdfPage)
pdfView.go(to: cgRect, on: pdfPage)
are producing the same effect (the effect in the first image).
After you create the PDFviewer center the view like this
let pdfView = PDFView(frame: viewFA.view.bounds)
pdfView.center.y = viewFA.view.center.y - 100

MKMapView's scale is not shown

I'm doing an iOS application. In Xcode 9.1 I create a MKMapView by
let mapView = MKMapView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: view.bounds.height))
mapView.isUserInteractionEnabled = false
mapView.mapType = .satellite
mapView.showsCompass = false
mapView.showsScale = true
view.addSubview(mapView)
but when I run it in the simulator the scale is not shown and I get three messages in the log:
Could not inset compass from edges 9
Could not inset scale from edge 9
Could not inset legal attribution from corner 4
The compass is not shown (as expected) but it's not shown if I change mapView.showsCompass to trueeither. However, the Legal link is shown. What am I missing here? I'm guessing it's something about the new safe areas introduced with iOS 11, but I fail to see how that is important for a view I want to be covering the whole screen.
In iOS 10 or lower
As #Paulw11 says, the scale is only shown while zooming by default.
In iOS 11
You can use scaleVisibility.
https://developer.apple.com/documentation/mapkit/mkscaleview/2890254-scalevisibility
let scale = MKScaleView(mapView: mapView)
scale.scaleVisibility = .visible // always visible
view.addSubview(scale)
had the same problem with the scale today. I want that scale visible all the time. Cost me several hours to solve it. So I add the code here, just in case, someone run into the same issue.
Got some hints:
from this thread: Use Safe Area Layout programmatically
and this website: Pain Free Constraints with Layout Anchors
Happy coding ...
Hardy
// "self.MapOnScreen" refers to the map currently displayed
// check if we have to deal with the scale
if #available(iOS 11.0, *) {
// as we will change the UI, ensure it's on main thread
DispatchQueue.main.async(execute: {
// switch OFF the standard scale (otherwise both will be visible when zoom in/out)
self.MapOnScreen.showsScale = false
// build the view
let scale = MKScaleView(mapView: self.MapOnScreen)
// we want to use autolayout
scale.translatesAutoresizingMaskIntoConstraints = false
// scale should be visible all the time
scale.scaleVisibility = .visible // always visible
// add it to the map
self.MapOnScreen.addSubview(scale)
// get the current safe area of the map
let guide = self.MapOnScreen.safeAreaLayoutGuide
// Activate this array of constraints, which at the time removes leftovers if any
NSLayoutConstraint.activate(
[
// LEFT (I do not want a change if right-to-left language) margin with an offset to safe area
// alternative would be ".leadingAnchor", which switches to the right margin, if right-to-left language is used
scale.leftAnchor.constraint(equalTo: guide.leftAnchor, constant: 16.0),
// right edge will be the middle of the map
scale.rightAnchor.constraint(equalTo: guide.centerXAnchor),
// top margin is the top safe area
scale.topAnchor.constraint(equalTo: guide.topAnchor),
// view will be 20 points high
scale.heightAnchor.constraint(equalToConstant: 20.0)
]
)
})
}
Objective c equivalent:-
if (#available(iOS 11.0, *)) {
// switch OFF the standard scale (otherwise both will be visible when zoom in/out)
self.map.showsScale = false;
// build the view
MKScaleView* scale = [MKScaleView scaleViewWithMapView:self.map];
// we want to use autolayout
scale.translatesAutoresizingMaskIntoConstraints = false;
// scale should be visible all the time
scale.scaleVisibility = MKFeatureVisibilityVisible;// always visible
// add it to the map
[self.view addSubview:scale];
// get the current safe area of the map
UILayoutGuide * guide = self.view.safeAreaLayoutGuide;
// Activate this array of constraints, which at the time removes leftovers if any
[NSLayoutConstraint activateConstraints:
#[
// LEFT (I do not want a change if right-to-left language) margin with an offset to safe area
// alternative would be ".leadingAnchor", which switches to the right margin, if right-to-left language is used
//[scale.leftAnchor constraintEqualToAnchor: guide.centerXAnchor constant: -(scale.frame.size.width/2.0)],
// right edge will be the middle of the map
[scale.rightAnchor constraintEqualToAnchor: guide.centerXAnchor constant: (scale.frame.size.width/2.0)],
// top margin is the top safe area
[scale.bottomAnchor constraintEqualToAnchor: guide.bottomAnchor constant:-self.toolBar.frame.size.height],
// view will be 20 points high
[scale.heightAnchor constraintEqualToConstant: 50.0]
]
];
[self.view bringSubviewToFront:scale];
}

Resources