About iOS14 of PencilKit - ios14

environment
・MacOS: 10.15.7
・Xcode: 12.1
・iOS: 14.1
I am trying to PencilKit and but I cannot show PKToolPicker. I set my code as below:
if let window = UIApplication.shared.windows.first {
if let toolPicker = PKToolPicker.shared(for: window) {
toolPicker.addObserver(canvas)
toolPicker.setVisible(true, forFirstResponder: canvas)
canvas.becomeFirstResponder()
}
}
I get a warning here:
'shared(for:)' was deprecated in iOS 14.0: Create individual instances instead.
So I changed it like this
let toolPicker = PKToolPicker.init()
toolPicker.addObserver(canvas)
toolPicker.setVisible(true, forFirstResponder: canvas)
canvas.becomeFirstResponder()
After all the PKToolPicker is not displayed
I am aiming to display such PKToolPicker
Please give me advice

First declare an individual instance of the toolPicker for the ViewController at the class level. This is required to be able to change pens in the toolPicker:
let toolPicker = PKToolPicker()
Then later, in viewWillAppear(_ :)
toolPicker.addObserver(canvas)
toolPicker.setVisible(true, forFirstResponder: canvas)
canvas.becomeFirstResponder()

I solved it like this
toolPicker.addObserver(canvas)
toolPicker.setVisible(true, forFirstResponder: canvas)
canvas.becomeFirstResponder()

Related

Adding textfeilds on top of drawing veiw image XCode SwiftUI

Essentially I would like to add text fields on top of my image.
Currently, my viewDidLoad() is currently set up as such.
-Image Background (UIImage)
--Drawing Canvas
I would like it to be set up as such so that it is not possible to draw over the text fields, as I realize it is possible to add text over the image itself
-Image Background (UIImage)
---Drawing Canvas
-----TextFeild Struct
I would assume I need to use UITextField but I keep on getting this error in my simulation.
(Fatal error: Unexpectedly found nil while implicitly unwrapping an
Optional value)
In addition to this error, I'm unable to edit the scaling of my image background. I tried everything turning the imageView to content mode, and modifying the image before adding the view (scaleAspectFit/scaleAspectFill), resizing the view the only thing that seemed to work was changing the resolution of the source image.
I would like to add text fields up top right
class DrawingCanvasViewController: UIViewController {
#IBOutlet weak var nameTextField: UITextField!
lazy var canvas: PKCanvasView = {
let view = PKCanvasView()
view.drawingPolicy = .anyInput
view.minimumZoomScale = 1
view.maximumZoomScale = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var toolPicker: PKToolPicker = {
let toolPicker = PKToolPicker()
toolPicker.addObserver(self)
return toolPicker
}()
var drawingData = Data()
var drawingChanged: (Data) -> Void = {_ in}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(canvas)
canvas.backgroundColor = .clear
let iTest=UIImage(named: "Test2")
let imageView=UIImageView(image: iTest)
//This is what I have used for trying to resize my background image, although none of it seems to ever work
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
view.sendSubviewToBack(imageView)
//The fatal error it gives me is from these two lines below
// view.addSubview(nameTextField)
// view.bringSubviewToFront(nameTextField)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
toolPicker.setVisible(true, forFirstResponder: canvas)
toolPicker.addObserver(canvas)
canvas.delegate = self
canvas.becomeFirstResponder()
if let drawing = try? PKDrawing(data: drawingData){
canvas.drawing = drawing
}
}
}
I'm new to Xcode, I did follow a tutorial to add the pencil kit UI although am currently unable to refind it, and I figured out how to add the background image from looking at apple documentation, Hence I may have simply missed an easier/better way to code my app.
what I'm seeing from your code is: that you added UITextField in your Xib/Storyboard file. Therefore you can remove the reference of UITextField in the Xib/Storyboard file with the controller and introduce UITextField programmatically. My solution below will only address the fatal error from the 2 lines:
view.addSubview(nameTextField)
view.bringSubviewToFront(nameTextField)
Then let me know other issues when you get this one working first. Please adjust the contrainst of nameTextField to have it visible.
class DrawingCanvasViewController: UIViewController {
// initialise text field
lazy var nameTextField: UITextField = {
let textField = UITextField()
textField.translatesAutoresizingMaskIntoConstraints = false
// Please setup delegate by yourself
return textField
}()
lazy var canvas: PKCanvasView = {
let view = PKCanvasView()
view.drawingPolicy = .anyInput
view.minimumZoomScale = 1
view.maximumZoomScale = 1
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
lazy var toolPicker: PKToolPicker = {
let toolPicker = PKToolPicker()
toolPicker.addObserver(self)
return toolPicker
}()
var drawingData = Data()
var drawingChanged: (Data) -> Void = {_ in}
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(canvas)
canvas.backgroundColor = .clear
let iTest=UIImage(named: "Test2")
let imageView=UIImageView(image: iTest)
//This is what I have used for trying to resize my background image,
// although none of it seems to ever work
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.contentMode = .scaleAspectFit
view.addSubview(imageView)
view.sendSubviewToBack(imageView)
// since you already created the nameTextField as a lazy variable
// then you can add it here
view.addSubview(nameTextField)
view.bringSubviewToFront(nameTextField)
NSLayoutConstraint.activate([
canvas.leadingAnchor.constraint(equalTo: view.leadingAnchor),
canvas.trailingAnchor.constraint(equalTo: view.trailingAnchor),
canvas.topAnchor.constraint(equalTo: view.topAnchor),
canvas.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
toolPicker.setVisible(true, forFirstResponder: canvas)
toolPicker.addObserver(canvas)
canvas.delegate = self
canvas.becomeFirstResponder()
if let drawing = try? PKDrawing(data: drawingData){
canvas.drawing = drawing
}
}
}

Swift PDFKit: Inconsistent behaviour with PDFView.currentDestination and PDFView.go(to destination: PDFDestination)

Note: The question remains unsolved for now; the marked answer provides a good workaround - it works while the application is still open. Answers are still welcomed!
Background
I'm currently developing an app that consists of a full-screen PDFView, and I want the program to remember the position in the document before the view is dismissed so the user can pick up where they've left.
Implementation
A simplified version of the app can be understood as a PDF Viewer using PDFKit.PDFView. The storyboard consists of an UIView that's connected to a PDFView class, DocumentView (which conforms to UIViewController). The view is initialised through the following process:
In viewDidLoad:
let PDF: PDFDocument = GetPDFFromServer()
DocumentView.document = PDF!
DocumentView.autoScales = true
... (other settings)
// Set PDF Destination
let Destination: PDFDestination = GetStoredDestination()
// Code with issues
DocumentView.go(to: Destination)
In viewWillDisappear:
StoreDestination(DocumentView.currentDestination)
The Issue & Tests
I realised that the code does not work as expected; the view does not return to its previous location.
Through debugging, I realised that this might be due to the inconsistent behaviour of DocumentView.go(to destination: PDFDestination) and DocumentView.currentDestination.
To ensure the bug is not introduced by errors while storing the location, the following code is used to verify the issue, with a multi-page document:
In viewDidLoad
Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
DispatchQueue.main.async {
self.DocumentView.go(to:self.DocumentView.currentDestination!)
}
})
Expected & Observed behaviour
Expected: The location of the document should not change - the code is going to its current destination every 1 second which should have no effects. as "currentDestination" should be the "current destination of the document, per docs")
Observed: Upon execution, the page would spontaneously scroll down by a fixed offset.
The same outcome was observed on an iPadOS 14.5 simulator and an iPadOS 15 iPad Air (Gen 4).
What might have gone wrong?
It'd be great if somebody can help.
Cheers,
Lincoln
This question was originally published on the Apple Developer Forum over a week ago; No responses were heard for over a week, so I thought I might try my luck here on StackOverflow <3
I tried PDFView.go() for this scenario and I managed to get it work for some cases but found that it fails in some other scenarios such as with zoomed documents, changed orientations.
So going back to what you are trying to achieve,
I'm currently developing an app that consists of a full-screen
PDFView, and I want the program to remember the position in the
document before the view is dismissed so the user can pick up where
they've left.
this can be done from a different approach. With this approach, you need to always keep a reference to the PDFView you created. If the previous pdf needs to be loaded again, then you pass the PDFView instance you have to the viewController as it is. Otherwise you load the new pdf to the PDFView instance and pass it to the viewController.
DocumentViewController gets the PDFView when it gets initialized.
import UIKit
import PDFKit
protocol DocumentViewControllerDelegate: AnyObject {
func needsContinuePDF(continuePDF: Bool)
}
class DocumentViewController: UIViewController {
var pdfView: PDFView!
weak var delegate: DocumentViewControllerDelegate!
init(pdfView: PDFView, delegate: DocumentViewControllerDelegate){
self.pdfView = pdfView
self.delegate = delegate
super.init(nibName: nil, bundle: nil)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func loadView() {
super.loadView()
self.view.backgroundColor = .white
view.addSubview(pdfView)
NSLayoutConstraint.activate([
pdfView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
pdfView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
pdfView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
pdfView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
}
override func viewWillDisappear(_ animated: Bool) {
delegate.needsContinuePDF(continuePDF: true)
}
}
You can initialize DocumentViewController like below. MainViewController has the responsibility for initializing PDFView.
import UIKit
import PDFKit
class MainViewController: UIViewController {
var pdfView: PDFView = PDFView()
var continuePreviousPDF = false
let button = UIButton(frame: .zero)
override func loadView() {
super.loadView()
button.setTitle("View PDF", for: .normal)
button.setTitleColor(.white, for: .normal)
button.backgroundColor = .systemBlue
button.addTarget(self, action: #selector(openDocumentView(_:)), for: .touchUpInside)
self.view.backgroundColor = .systemGray5
self.view.addSubview(button)
button.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalToConstant: 100),
button.heightAnchor.constraint(equalToConstant: 50),
button.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor),
button.centerYAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerYAnchor),
])
}
#objc func openDocumentView(_ sender: UIButton) {
//open a nee PDF if not continue previous one
if !self.continuePreviousPDF {
pdfView.autoScales = true
pdfView.displayMode = .singlePageContinuous
pdfView.translatesAutoresizingMaskIntoConstraints = false
guard let path = Bundle.main.url(forResource: "sample copy", withExtension: "pdf") else { return }
if let document = PDFDocument(url: path) {
pdfView.document = document
}
}
let documentViewController = DocumentViewController(pdfView: pdfView, delegate: self)
self.present(documentViewController, animated: true, completion: nil)
}
}
extension MainViewController: DocumentViewControllerDelegate {
func needsContinuePDF(continuePDF: Bool) {
self.continuePreviousPDF = continuePDF
}
}

Why Today App Extension Widget in SwiftUI is white?

just like this
and my view is simply:
Text("Testing Widget")
and tried this:
VStack {
Text("Testing Widget")
}
.background(Color(UIColor.clear))
and nothing happend:(.
Just came across a solution for me!
You have to set the backgroundColor of the UIHostingController's view to .clear, and then it will work. You don't need to set the background color of the SwiftUI view.
let hostingController = UIHostingController(rootView: SwiftUIView())
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.addSubview(hostingController.view)
addChild(hostingController)
hostingController.didMove(toParent: self)
// You may want to add constraints
hostingController.view.backgroundColor = .clear // <- IMPORTANT
}

PencilKit toolPicker is not showing up

I am trying to create an app using PencilKit. I have the following code in one of my ViewControllers.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
guard
let window = view.window,
let toolPicker = PKToolPicker.shared(for: window) else { return }
toolPicker.setVisible(true, forFirstResponder: canvasView)
toolPicker.addObserver(canvasView)
canvasView.becomeFirstResponder()
}
Although I am calling the setVisible function and making the canvasView the firstResponder, my toolPicker is not showing up, and printing toolPicker.isVisible is false.
Move your code to viewWillAppear(), this did it for me.
Apple is also doing it. I recommend to download and play with the Sample Code provided by Apple.

How should be defined the options dictionary for PDFView usePageViewController withViewOptions:

How should be defined a dictionary of options for a pageViewController for a PDFView from PDFKit?
I am interested particulari with this flag
UIPageViewController.NavigationOrientation.horizontal
let pdfv = PDFView.init(frame: self.view.frame)
let opt = ?????
pdfv.usePageViewController(true, withViewOptions: opt)
The ViewOptions contains only 2 options: interPageSpacing and spineLocation: https://developer.apple.com/documentation/uikit/uipageviewcontroller/optionskey
Exemple: pdfv.usePageViewController(true, withViewOptions: ["interPageSpacing": 50])
If you want to change the pageViewController direction to horizontal, use this code:
pdfv.displayDirection = .horizontal
Hope this helps.

Resources